Partially implements blueprint psr-2
Change-Id: Ifd8b7237f650f0f18fa58ab0e870eb2774c776fc
This commit is contained in:
parent
948eb89ba8
commit
e5c695f72a
@ -1,7 +1,6 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../src/OpenStack/Autoloader.php';
|
||||
|
||||
use \OpenStack\Bootstrap;
|
||||
use \OpenStack\Autoloader;
|
||||
use \OpenStack\Services\IdentityService;
|
||||
use \OpenStack\Storage\ObjectStorage;
|
||||
@ -38,6 +37,3 @@ printf("Name: %s \n", $object->name());
|
||||
printf("Size: %d \n", $object->contentLength());
|
||||
printf("Type: %s \n", $object->contentType());
|
||||
print $object->content() . PHP_EOL;
|
||||
|
||||
|
||||
|
||||
|
@ -8,10 +8,10 @@ Bootstrap::useStreamWrappers();
|
||||
|
||||
$ini = parse_ini_file(getenv('HOME') . '/.OpenStack.ini');
|
||||
$settings = array(
|
||||
'account' => $ini['account'],
|
||||
'key' => $ini['secret'],
|
||||
'tenantid' => $ini['tenantId'],
|
||||
'endpoint' => $ini['url'],
|
||||
'account' => $ini['account'],
|
||||
'key' => $ini['secret'],
|
||||
'tenantid' => $ini['tenantId'],
|
||||
'endpoint' => $ini['url'],
|
||||
);
|
||||
Bootstrap::setConfiguration($settings);
|
||||
|
||||
@ -22,7 +22,7 @@ fclose($newfile);
|
||||
|
||||
// Check for an object:
|
||||
if (file_exists('swift://Example/my_file.txt')) {
|
||||
print "Found my_file.txt." . PHP_EOL;
|
||||
print "Found my_file.txt." . PHP_EOL;
|
||||
}
|
||||
|
||||
// Get an entire object at once:
|
||||
@ -30,13 +30,12 @@ $file = file_get_contents('swift://Example/my_file.txt');
|
||||
print 'File: ' . $file . PHP_EOL;
|
||||
|
||||
$cxt = stream_context_create(array(
|
||||
'swift' => array(
|
||||
'account' => $ini['account'],
|
||||
'key' => $ini['secret'],
|
||||
'tenantid' => $ini['tenantId'],
|
||||
'endpoint' => $ini['url'],
|
||||
),
|
||||
'swift' => array(
|
||||
'account' => $ini['account'],
|
||||
'key' => $ini['secret'],
|
||||
'tenantid' => $ini['tenantId'],
|
||||
'endpoint' => $ini['url'],
|
||||
),
|
||||
));
|
||||
|
||||
print file_get_contents('swift://Example/my_file.txt', FALSE, $cxt);
|
||||
|
||||
|
@ -2,17 +2,17 @@
|
||||
/* ============================================================================
|
||||
(c) Copyright 2014 Hewlett-Packard Development Company, L.P.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
============================================================================ */
|
||||
/**
|
||||
* An Autoloader to use for the case Composer isn't available.
|
||||
@ -44,74 +44,77 @@ namespace OpenStack;
|
||||
*/
|
||||
Class Autoloader {
|
||||
|
||||
/**
|
||||
* @var string The directory where OpenStack is located.
|
||||
*/
|
||||
public static $basedir = __DIR__;
|
||||
/**
|
||||
* @var string The directory where OpenStack is located.
|
||||
*/
|
||||
public static $basedir = __DIR__;
|
||||
|
||||
/**
|
||||
* Add the autoloader to PHP's autoloader list.
|
||||
*
|
||||
* This will add the internal special-purpose
|
||||
* autoloader to the list of autoloaders that PHP will
|
||||
* leverage to resolve class paths.
|
||||
*
|
||||
* Because OpenStack is PSR-4 compliant, any
|
||||
* full PSR-4 classloader should be capable of loading
|
||||
* these classes witout issue. You may prefer to use
|
||||
* a standard PSR-4 loader instead of this one.
|
||||
*
|
||||
* @see https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4.md
|
||||
*/
|
||||
public static function useAutoloader() {
|
||||
spl_autoload_register(__NAMESPACE__ . '\Autoloader::autoload');
|
||||
}
|
||||
|
||||
/**
|
||||
* OpenStack autoloader.
|
||||
*
|
||||
* An implementation of a PHP autoload function. Use
|
||||
* OpenStack::useAutoloader() if you want PHP to automatically
|
||||
* load classes using this autoloader.
|
||||
*
|
||||
* // Enable the autoloader.
|
||||
* Autoloader::useAutoloader();
|
||||
*
|
||||
* This is a special-purpose autoloader for loading
|
||||
* only the OpenStack classes. It will not attempt to
|
||||
* autoload anything outside of the OpenStack namespace.
|
||||
*
|
||||
* Because this is a special-purpose autoloader, it
|
||||
* should be safe to use with other special-purpose
|
||||
* autoloaders (and also projects that don't
|
||||
* rely upon autoloaders).
|
||||
*
|
||||
* @param string $klass The fully qualified name of the class to be autoloaded.
|
||||
*/
|
||||
public static function autoload($klass) {
|
||||
$components = explode('\\', $klass);
|
||||
if (empty($components[0])) {
|
||||
array_shift($components);
|
||||
/**
|
||||
* Add the autoloader to PHP's autoloader list.
|
||||
*
|
||||
* This will add the internal special-purpose
|
||||
* autoloader to the list of autoloaders that PHP will
|
||||
* leverage to resolve class paths.
|
||||
*
|
||||
* Because OpenStack is PSR-4 compliant, any
|
||||
* full PSR-4 classloader should be capable of loading
|
||||
* these classes witout issue. You may prefer to use
|
||||
* a standard PSR-4 loader instead of this one.
|
||||
*
|
||||
* @see https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4.md
|
||||
*/
|
||||
public static function useAutoloader()
|
||||
{
|
||||
spl_autoload_register(__NAMESPACE__ . '\Autoloader::autoload');
|
||||
}
|
||||
|
||||
// This class loader ONLY loads
|
||||
// our classes. A general purpose
|
||||
// classloader should be used for
|
||||
// more sophisticated needs.
|
||||
if ($components[0] != 'OpenStack') {
|
||||
return;
|
||||
/**
|
||||
* OpenStack autoloader.
|
||||
*
|
||||
* An implementation of a PHP autoload function. Use
|
||||
* OpenStack::useAutoloader() if you want PHP to automatically
|
||||
* load classes using this autoloader.
|
||||
*
|
||||
* // Enable the autoloader.
|
||||
* Autoloader::useAutoloader();
|
||||
*
|
||||
* This is a special-purpose autoloader for loading
|
||||
* only the OpenStack classes. It will not attempt to
|
||||
* autoload anything outside of the OpenStack namespace.
|
||||
*
|
||||
* Because this is a special-purpose autoloader, it
|
||||
* should be safe to use with other special-purpose
|
||||
* autoloaders (and also projects that don't
|
||||
* rely upon autoloaders).
|
||||
*
|
||||
* @param string $klass The fully qualified name of the class to be autoloaded.
|
||||
*/
|
||||
public static function autoload($klass)
|
||||
{
|
||||
$components = explode('\\', $klass);
|
||||
if (empty($components[0])) {
|
||||
array_shift($components);
|
||||
}
|
||||
|
||||
// This class loader ONLY loads
|
||||
// our classes. A general purpose
|
||||
// classloader should be used for
|
||||
// more sophisticated needs.
|
||||
if ($components[0] != 'OpenStack') {
|
||||
return;
|
||||
}
|
||||
|
||||
// We need the path up to, but not including, the root OpenStack dir:
|
||||
$loc = DIRECTORY_SEPARATOR . 'OpenStack';
|
||||
$local_path = substr(self::$basedir, 0, strrpos(self::$basedir, $loc));
|
||||
|
||||
array_unshift($components, $local_path);
|
||||
$path = implode(DIRECTORY_SEPARATOR, $components) . '.php';
|
||||
|
||||
if (file_exists($path)) {
|
||||
require $path;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// We need the path up to, but not including, the root OpenStack dir:
|
||||
$loc = DIRECTORY_SEPARATOR . 'OpenStack';
|
||||
$local_path = substr(self::$basedir, 0, strrpos(self::$basedir, $loc));
|
||||
|
||||
array_unshift($components, $local_path);
|
||||
$path = implode(DIRECTORY_SEPARATOR, $components) . '.php';
|
||||
|
||||
if (file_exists($path)) {
|
||||
require $path;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,17 +2,17 @@
|
||||
/* ============================================================================
|
||||
(c) Copyright 2012-2014 Hewlett-Packard Development Company, L.P.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
============================================================================ */
|
||||
/**
|
||||
* OpenStack SDK for PHP configuration.
|
||||
@ -23,7 +23,6 @@
|
||||
namespace OpenStack;
|
||||
|
||||
use OpenStack\Services\IdentityService;
|
||||
use OpenStack\Exception;
|
||||
|
||||
/**
|
||||
* Bootstrapping services.
|
||||
@ -80,204 +79,207 @@ use OpenStack\Exception;
|
||||
*
|
||||
* It's awesome. Trust me.
|
||||
*/
|
||||
class Bootstrap {
|
||||
|
||||
public static $config = array(
|
||||
// The transport implementation. By default, we use the Guzzle Client
|
||||
'transport' => '\OpenStack\Transport\GuzzleClient',
|
||||
);
|
||||
|
||||
/**
|
||||
* @var \OpenStack\Services\IdentityService An identity services object
|
||||
* created from the global settings.
|
||||
*/
|
||||
public static $identity = NULL;
|
||||
|
||||
/**
|
||||
* @var \OpenStack\Transport\ClientInterface A transport client for requests.
|
||||
*/
|
||||
public static $transport = NULL;
|
||||
|
||||
/**
|
||||
* Register stream wrappers for OpenStack.
|
||||
*
|
||||
* This registers the ObjectStorage stream wrappers, which allow you to access
|
||||
* ObjectStorage through standard file access mechanisms.
|
||||
*
|
||||
* // Enable stream wrapper.
|
||||
* Bootstrap::useStreamWrappers();
|
||||
*
|
||||
* // Create a context resource.
|
||||
* $cxt = stream_context_create(array(
|
||||
* 'tenantid' => '12de21',
|
||||
* 'username' => 'foobar',
|
||||
* 'password' => 'f78saf7hhlll',
|
||||
* 'endpoint' => 'https://identity.hpcloud.com' // <-- not real URL!
|
||||
* ));
|
||||
*
|
||||
* // Get the contents of a Swift object.
|
||||
* $content = file_get_contents('swift://public/notes.txt', 'r', FALSE, $cxt);
|
||||
*/
|
||||
public static function useStreamWrappers() {
|
||||
$swift = stream_wrapper_register(
|
||||
\OpenStack\Storage\ObjectStorage\StreamWrapper::DEFAULT_SCHEME,
|
||||
'\OpenStack\Storage\ObjectStorage\StreamWrapper'
|
||||
class Bootstrap
|
||||
{
|
||||
public static $config = array(
|
||||
// The transport implementation. By default, we use the Guzzle Client
|
||||
'transport' => '\OpenStack\Transport\GuzzleClient',
|
||||
);
|
||||
|
||||
$swiftfs = stream_wrapper_register(
|
||||
\OpenStack\Storage\ObjectStorage\StreamWrapperFS::DEFAULT_SCHEME,
|
||||
'\OpenStack\Storage\ObjectStorage\StreamWrapperFS'
|
||||
);
|
||||
/**
|
||||
* @var \OpenStack\Services\IdentityService An identity services object
|
||||
* created from the global settings.
|
||||
*/
|
||||
public static $identity = NULL;
|
||||
|
||||
return ($swift && $swiftfs);
|
||||
}
|
||||
/**
|
||||
* @var \OpenStack\Transport\ClientInterface A transport client for requests.
|
||||
*/
|
||||
public static $transport = NULL;
|
||||
|
||||
/**
|
||||
* Set configuration directives for OpenStack.
|
||||
*
|
||||
* This merges the provided associative array into the existing
|
||||
* configuration parameters (Bootstrap::$config).
|
||||
*
|
||||
* All of the OpenStack classes share the same configuration. This
|
||||
* ensures that a stable runtime environment is maintained.
|
||||
*
|
||||
* Common configuration directives:
|
||||
*
|
||||
* - 'transport': The namespaced classname for the transport that
|
||||
* should be used. Example: @code \OpenStack\Transport\CURLTransport @endcode
|
||||
* - 'transport.debug': The integer 1 for enabling debug, 0 for
|
||||
* disabling. Enabling will turn on verbose debugging output
|
||||
* for any transport that supports it.
|
||||
* - 'transport.timeout': An integer value indicating how long
|
||||
* the transport layer should wait for an HTTP request. A
|
||||
* transport MAY ignore this parameter, but the ones included
|
||||
* with the library honor it.
|
||||
* - 'transport.ssl_verify': Set this to FALSE to turn off SSL certificate
|
||||
* verification. This is NOT recommended, but is sometimes necessary for
|
||||
* certain proxy configurations.
|
||||
* - 'transport.proxy': Set the proxy as a string.
|
||||
* - 'username' and 'password'
|
||||
* - 'tenantid'
|
||||
* - 'endpoint': The full URL to identity services. This is used by stream
|
||||
* wrappers.
|
||||
*
|
||||
* @param array $array An associative array of configuration directives.
|
||||
*/
|
||||
public static function setConfiguration($array) {
|
||||
self::$config = $array + self::$config;
|
||||
}
|
||||
/**
|
||||
* Register stream wrappers for OpenStack.
|
||||
*
|
||||
* This registers the ObjectStorage stream wrappers, which allow you to access
|
||||
* ObjectStorage through standard file access mechanisms.
|
||||
*
|
||||
* // Enable stream wrapper.
|
||||
* Bootstrap::useStreamWrappers();
|
||||
*
|
||||
* // Create a context resource.
|
||||
* $cxt = stream_context_create(array(
|
||||
* 'tenantid' => '12de21',
|
||||
* 'username' => 'foobar',
|
||||
* 'password' => 'f78saf7hhlll',
|
||||
* 'endpoint' => 'https://identity.hpcloud.com' // <-- not real URL!
|
||||
* ));
|
||||
*
|
||||
* // Get the contents of a Swift object.
|
||||
* $content = file_get_contents('swift://public/notes.txt', 'r', FALSE, $cxt);
|
||||
*/
|
||||
public static function useStreamWrappers()
|
||||
{
|
||||
$swift = stream_wrapper_register(
|
||||
\OpenStack\Storage\ObjectStorage\StreamWrapper::DEFAULT_SCHEME,
|
||||
'\OpenStack\Storage\ObjectStorage\StreamWrapper'
|
||||
);
|
||||
|
||||
/**
|
||||
* Get a configuration option.
|
||||
*
|
||||
* Get a configuration option by name, with an optional default.
|
||||
*
|
||||
* @param string $name The name of the configuration option to get.
|
||||
* @param mixed $default The default value to return if the name is not found.
|
||||
*
|
||||
* @return mixed The value, if found; or the default, if set; or NULL.
|
||||
*/
|
||||
public static function config($name = NULL, $default = NULL) {
|
||||
$swiftfs = stream_wrapper_register(
|
||||
\OpenStack\Storage\ObjectStorage\StreamWrapperFS::DEFAULT_SCHEME,
|
||||
'\OpenStack\Storage\ObjectStorage\StreamWrapperFS'
|
||||
);
|
||||
|
||||
// If no name is specified, return the entire config array.
|
||||
if (empty($name)) {
|
||||
return self::$config;
|
||||
return ($swift && $swiftfs);
|
||||
}
|
||||
|
||||
// If the config value exists, return that.
|
||||
if (isset(self::$config[$name])) {
|
||||
return self::$config[$name];
|
||||
/**
|
||||
* Set configuration directives for OpenStack.
|
||||
*
|
||||
* This merges the provided associative array into the existing
|
||||
* configuration parameters (Bootstrap::$config).
|
||||
*
|
||||
* All of the OpenStack classes share the same configuration. This
|
||||
* ensures that a stable runtime environment is maintained.
|
||||
*
|
||||
* Common configuration directives:
|
||||
*
|
||||
* - 'transport': The namespaced classname for the transport that
|
||||
* should be used. Example: @code \OpenStack\Transport\CURLTransport @endcode
|
||||
* - 'transport.debug': The integer 1 for enabling debug, 0 for
|
||||
* disabling. Enabling will turn on verbose debugging output
|
||||
* for any transport that supports it.
|
||||
* - 'transport.timeout': An integer value indicating how long
|
||||
* the transport layer should wait for an HTTP request. A
|
||||
* transport MAY ignore this parameter, but the ones included
|
||||
* with the library honor it.
|
||||
* - 'transport.ssl_verify': Set this to FALSE to turn off SSL certificate
|
||||
* verification. This is NOT recommended, but is sometimes necessary for
|
||||
* certain proxy configurations.
|
||||
* - 'transport.proxy': Set the proxy as a string.
|
||||
* - 'username' and 'password'
|
||||
* - 'tenantid'
|
||||
* - 'endpoint': The full URL to identity services. This is used by stream
|
||||
* wrappers.
|
||||
*
|
||||
* @param array $array An associative array of configuration directives.
|
||||
*/
|
||||
public static function setConfiguration($array)
|
||||
{
|
||||
self::$config = $array + self::$config;
|
||||
}
|
||||
|
||||
// Otherwise, just return the default value.
|
||||
return $default;
|
||||
}
|
||||
/**
|
||||
* Get a configuration option.
|
||||
*
|
||||
* Get a configuration option by name, with an optional default.
|
||||
*
|
||||
* @param string $name The name of the configuration option to get.
|
||||
* @param mixed $default The default value to return if the name is not found.
|
||||
*
|
||||
* @return mixed The value, if found; or the default, if set; or NULL.
|
||||
*/
|
||||
public static function config($name = NULL, $default = NULL)
|
||||
{
|
||||
// If no name is specified, return the entire config array.
|
||||
if (empty($name)) {
|
||||
return self::$config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the given configuration option is set.
|
||||
*
|
||||
* if (Bootstrap::hasConfig('transport')) {
|
||||
* syslog(LOG_INFO, 'An alternate transport is supplied.');
|
||||
* }
|
||||
*
|
||||
* @param string $name The name of the item to check for.
|
||||
*
|
||||
* @return boolean TRUE if the named option is set, FALSE otherwise. Note that
|
||||
* the value may be falsey (FALSE, 0, etc.), but if the value is NULL, this
|
||||
* will return false.
|
||||
*/
|
||||
public static function hasConfig($name) {
|
||||
return isset(self::$config[$name]);
|
||||
}
|
||||
// If the config value exists, return that.
|
||||
if (isset(self::$config[$name])) {
|
||||
return self::$config[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a \OpenStack\Services\IdentityService object from the bootstrap config.
|
||||
*
|
||||
* A factory helper function that uses the bootstrap configuration to create
|
||||
* a ready to use \OpenStack\Services\IdentityService object.
|
||||
*
|
||||
* @param bool $force Whether to force the generation of a new object even if
|
||||
* one is already cached.
|
||||
*
|
||||
* @return \OpenStack\Services\IdentityService An authenticated ready to use
|
||||
* \OpenStack\Services\IdentityService object.
|
||||
* @throws \OpenStack\Exception When the needed configuration to authenticate
|
||||
* is not available.
|
||||
*/
|
||||
public static function identity($force = FALSE) {
|
||||
|
||||
$transport = self::transport();
|
||||
|
||||
// If we already have an identity make sure the token is not expired.
|
||||
if ($force || is_null(self::$identity) || self::$identity->isExpired()) {
|
||||
|
||||
// Make sure we have an endpoint to use
|
||||
if (!self::hasConfig('endpoint')) {
|
||||
throw new Exception('Unable to authenticate. No endpoint supplied.');
|
||||
}
|
||||
|
||||
// User cannot be an empty string, so we need
|
||||
// to do more checking than self::hasConfig(), which returns TRUE
|
||||
// if an item exists and is an empty string.
|
||||
$user = self::config('username', NULL);
|
||||
|
||||
// Check if we have a username/password
|
||||
if (!empty($user) && self::hasConfig('password')) {
|
||||
$is = new IdentityService(self::config('endpoint'), $transport);
|
||||
$is->authenticateAsUser($user, self::config('password'), self::config('tenantid', NULL), self::config('tenantname', NULL));
|
||||
self::$identity = $is;
|
||||
}
|
||||
else {
|
||||
throw new Exception('Unable to authenticate. No user credentials supplied.');
|
||||
}
|
||||
// Otherwise, just return the default value.
|
||||
return $default;
|
||||
}
|
||||
|
||||
return self::$identity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a transport client.
|
||||
*
|
||||
* @param boolean $reset Whether to recreate the transport client if one already exists.
|
||||
* @return \OpenStack\Transport\ClientInterface A transport client.
|
||||
*/
|
||||
public static function transport($reset = FALSE) {
|
||||
|
||||
if (is_null(self::$transport) || $reset == TRUE) {
|
||||
$options = [
|
||||
'ssl_verify' => self::config('ssl_verify', TRUE),
|
||||
'timeout' => self::config('timeout', 0), // 0 is no timeout.
|
||||
'debug' => self::config('debug', 0),
|
||||
];
|
||||
$proxy = self::config('proxy', FALSE);
|
||||
if ($proxy) {
|
||||
$options['proxy'] = $proxy;
|
||||
}
|
||||
|
||||
$klass = self::config('transport');
|
||||
self::$transport = new $klass($options);
|
||||
/**
|
||||
* Check whether the given configuration option is set.
|
||||
*
|
||||
* if (Bootstrap::hasConfig('transport')) {
|
||||
* syslog(LOG_INFO, 'An alternate transport is supplied.');
|
||||
* }
|
||||
*
|
||||
* @param string $name The name of the item to check for.
|
||||
*
|
||||
* @return boolean TRUE if the named option is set, FALSE otherwise. Note that
|
||||
* the value may be falsey (FALSE, 0, etc.), but if the value is NULL, this
|
||||
* will return false.
|
||||
*/
|
||||
public static function hasConfig($name)
|
||||
{
|
||||
return isset(self::$config[$name]);
|
||||
}
|
||||
|
||||
return self::$transport;
|
||||
}
|
||||
/**
|
||||
* Get a \OpenStack\Services\IdentityService object from the bootstrap config.
|
||||
*
|
||||
* A factory helper function that uses the bootstrap configuration to create
|
||||
* a ready to use \OpenStack\Services\IdentityService object.
|
||||
*
|
||||
* @param bool $force Whether to force the generation of a new object even if
|
||||
* one is already cached.
|
||||
*
|
||||
* @return \OpenStack\Services\IdentityService An authenticated ready to use
|
||||
* \OpenStack\Services\IdentityService object.
|
||||
* @throws \OpenStack\Exception When the needed configuration to authenticate
|
||||
* is not available.
|
||||
*/
|
||||
public static function identity($force = FALSE)
|
||||
{
|
||||
$transport = self::transport();
|
||||
|
||||
// If we already have an identity make sure the token is not expired.
|
||||
if ($force || is_null(self::$identity) || self::$identity->isExpired()) {
|
||||
|
||||
// Make sure we have an endpoint to use
|
||||
if (!self::hasConfig('endpoint')) {
|
||||
throw new Exception('Unable to authenticate. No endpoint supplied.');
|
||||
}
|
||||
|
||||
// User cannot be an empty string, so we need
|
||||
// to do more checking than self::hasConfig(), which returns TRUE
|
||||
// if an item exists and is an empty string.
|
||||
$user = self::config('username', NULL);
|
||||
|
||||
// Check if we have a username/password
|
||||
if (!empty($user) && self::hasConfig('password')) {
|
||||
$is = new IdentityService(self::config('endpoint'), $transport);
|
||||
$is->authenticateAsUser($user, self::config('password'), self::config('tenantid', NULL), self::config('tenantname', NULL));
|
||||
self::$identity = $is;
|
||||
} else {
|
||||
throw new Exception('Unable to authenticate. No user credentials supplied.');
|
||||
}
|
||||
}
|
||||
|
||||
return self::$identity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a transport client.
|
||||
*
|
||||
* @param boolean $reset Whether to recreate the transport client if one already exists.
|
||||
*
|
||||
* @return \OpenStack\Transport\ClientInterface A transport client.
|
||||
*/
|
||||
public static function transport($reset = FALSE)
|
||||
{
|
||||
if (is_null(self::$transport) || $reset == TRUE) {
|
||||
$options = [
|
||||
'ssl_verify' => self::config('ssl_verify', TRUE),
|
||||
'timeout' => self::config('timeout', 0), // 0 is no timeout.
|
||||
'debug' => self::config('debug', 0),
|
||||
];
|
||||
$proxy = self::config('proxy', FALSE);
|
||||
if ($proxy) {
|
||||
$options['proxy'] = $proxy;
|
||||
}
|
||||
|
||||
$klass = self::config('transport');
|
||||
self::$transport = new $klass($options);
|
||||
}
|
||||
|
||||
return self::$transport;
|
||||
}
|
||||
}
|
||||
|
@ -2,17 +2,17 @@
|
||||
/* ============================================================================
|
||||
(c) Copyright 2012-2014 Hewlett-Packard Development Company, L.P.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
============================================================================ */
|
||||
/**
|
||||
* The parent exception class for OpenStack.
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -2,17 +2,17 @@
|
||||
/* ============================================================================
|
||||
(c) Copyright 2012-2014 Hewlett-Packard Development Company, L.P.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
============================================================================ */
|
||||
/**
|
||||
* Contains the class for manipulating ObjectStorage ACL strings.
|
||||
@ -98,459 +98,471 @@ namespace OpenStack\Storage\ObjectStorage;
|
||||
* For a detailed description of the rules for ACL creation,
|
||||
* @see http://swift.openstack.org/misc.html#acls
|
||||
*/
|
||||
class ACL {
|
||||
class ACL
|
||||
{
|
||||
/**
|
||||
* Read flag.
|
||||
*
|
||||
* This is for an ACL of the READ type.
|
||||
*/
|
||||
const READ = 1;
|
||||
/**
|
||||
* Write flag.
|
||||
*
|
||||
* This is for an ACL of the WRITE type.
|
||||
*/
|
||||
const WRITE = 2;
|
||||
/**
|
||||
* Flag for READ and WRITE.
|
||||
*
|
||||
* This is equivalent to `ACL::READ | ACL::WRITE`
|
||||
*/
|
||||
const READ_WRITE = 3; // self::READ | self::WRITE;
|
||||
|
||||
/**
|
||||
* Read flag.
|
||||
*
|
||||
* This is for an ACL of the READ type.
|
||||
*/
|
||||
const READ = 1;
|
||||
/**
|
||||
* Write flag.
|
||||
*
|
||||
* This is for an ACL of the WRITE type.
|
||||
*/
|
||||
const WRITE = 2;
|
||||
/**
|
||||
* Flag for READ and WRITE.
|
||||
*
|
||||
* This is equivalent to `ACL::READ | ACL::WRITE`
|
||||
*/
|
||||
const READ_WRITE = 3; // self::READ | self::WRITE;
|
||||
/**
|
||||
* Header string for a read flag.
|
||||
*/
|
||||
const HEADER_READ = 'X-Container-Read';
|
||||
/**
|
||||
* Header string for a write flag.
|
||||
*/
|
||||
const HEADER_WRITE = 'X-Container-Write';
|
||||
|
||||
/**
|
||||
* Header string for a read flag.
|
||||
*/
|
||||
const HEADER_READ = 'X-Container-Read';
|
||||
/**
|
||||
* Header string for a write flag.
|
||||
*/
|
||||
const HEADER_WRITE = 'X-Container-Write';
|
||||
protected $rules = array();
|
||||
|
||||
protected $rules = array();
|
||||
/**
|
||||
* Allow READ access to the public.
|
||||
*
|
||||
* This grants the following:
|
||||
*
|
||||
* - READ to any host, with container listings.
|
||||
*
|
||||
* @return \OpenStack\Storage\ObjectStorage\ACL an ACL object with the
|
||||
* appopriate permissions set.
|
||||
*/
|
||||
public static function makePublic()
|
||||
{
|
||||
$acl = new ACL();
|
||||
$acl->addReferrer(self::READ, '*');
|
||||
$acl->allowListings();
|
||||
|
||||
/**
|
||||
* Allow READ access to the public.
|
||||
*
|
||||
* This grants the following:
|
||||
*
|
||||
* - READ to any host, with container listings.
|
||||
*
|
||||
* @return \OpenStack\Storage\ObjectStorage\ACL an ACL object with the
|
||||
* appopriate permissions set.
|
||||
*/
|
||||
public static function makePublic() {
|
||||
$acl = new ACL();
|
||||
$acl->addReferrer(self::READ, '*');
|
||||
$acl->allowListings();
|
||||
return $acl;
|
||||
}
|
||||
|
||||
return $acl;
|
||||
}
|
||||
/**
|
||||
* Disallow all public access.
|
||||
*
|
||||
* Non-public is the same as private. Private, however, is a reserved
|
||||
* word in PHP.
|
||||
*
|
||||
* This does not grant any permissions. OpenStack interprets an object
|
||||
* with no permissions as a private object.
|
||||
*
|
||||
* @return \OpenStack\Storage\ObjectStorage\ACL an ACL object with the
|
||||
* appopriate permissions set.
|
||||
*/
|
||||
public static function makeNonPublic()
|
||||
{
|
||||
// Default ACL is private.
|
||||
return new ACL();
|
||||
}
|
||||
|
||||
/**
|
||||
* Disallow all public access.
|
||||
*
|
||||
* Non-public is the same as private. Private, however, is a reserved
|
||||
* word in PHP.
|
||||
*
|
||||
* This does not grant any permissions. OpenStack interprets an object
|
||||
* with no permissions as a private object.
|
||||
*
|
||||
* @return \OpenStack\Storage\ObjectStorage\ACL an ACL object with the
|
||||
* appopriate permissions set.
|
||||
*/
|
||||
public static function makeNonPublic() {
|
||||
// Default ACL is private.
|
||||
return new ACL();
|
||||
}
|
||||
/**
|
||||
* Alias of ACL::makeNonPublic().
|
||||
*/
|
||||
public static function makePrivate()
|
||||
{
|
||||
return self::makeNonPublic();
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias of ACL::makeNonPublic().
|
||||
*/
|
||||
public static function makePrivate() {
|
||||
return self::makeNonPublic();
|
||||
}
|
||||
/**
|
||||
* Given a list of headers, get the ACL info.
|
||||
*
|
||||
* This is a utility for processing headers and discovering any ACLs embedded
|
||||
* inside the headers.
|
||||
*
|
||||
* @param array $headers An associative array of headers.
|
||||
*
|
||||
* @return \OpenStack\Storage\ObjectStorage\ACL A new ACL.
|
||||
*/
|
||||
public static function newFromHeaders($headers)
|
||||
{
|
||||
$acl = new ACL();
|
||||
|
||||
/**
|
||||
* Given a list of headers, get the ACL info.
|
||||
*
|
||||
* This is a utility for processing headers and discovering any ACLs embedded
|
||||
* inside the headers.
|
||||
*
|
||||
* @param array $headers An associative array of headers.
|
||||
*
|
||||
* @return \OpenStack\Storage\ObjectStorage\ACL A new ACL.
|
||||
*/
|
||||
public static function newFromHeaders($headers) {
|
||||
$acl = new ACL();
|
||||
|
||||
// READ rules.
|
||||
$rules = array();
|
||||
if (!empty($headers[self::HEADER_READ])) {
|
||||
$read = $headers[self::HEADER_READ];
|
||||
$rules = explode(',', $read);
|
||||
foreach ($rules as $rule) {
|
||||
$ruleArray = self::parseRule(self::READ, $rule);
|
||||
if (!empty($ruleArray)) {
|
||||
$acl->rules[] = $ruleArray;
|
||||
// READ rules.
|
||||
$rules = array();
|
||||
if (!empty($headers[self::HEADER_READ])) {
|
||||
$read = $headers[self::HEADER_READ];
|
||||
$rules = explode(',', $read);
|
||||
foreach ($rules as $rule) {
|
||||
$ruleArray = self::parseRule(self::READ, $rule);
|
||||
if (!empty($ruleArray)) {
|
||||
$acl->rules[] = $ruleArray;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WRITE rules.
|
||||
$rules = array();
|
||||
if (!empty($headers[self::HEADER_WRITE])) {
|
||||
$write = $headers[self::HEADER_WRITE];
|
||||
$rules = explode(',', $write);
|
||||
foreach ($rules as $rule) {
|
||||
$ruleArray = self::parseRule(self::WRITE, $rule);
|
||||
if (!empty($ruleArray)) {
|
||||
$acl->rules[] = $ruleArray;
|
||||
// WRITE rules.
|
||||
$rules = array();
|
||||
if (!empty($headers[self::HEADER_WRITE])) {
|
||||
$write = $headers[self::HEADER_WRITE];
|
||||
$rules = explode(',', $write);
|
||||
foreach ($rules as $rule) {
|
||||
$ruleArray = self::parseRule(self::WRITE, $rule);
|
||||
if (!empty($ruleArray)) {
|
||||
$acl->rules[] = $ruleArray;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//throw new \Exception(print_r($acl->rules(), TRUE));
|
||||
return $acl;
|
||||
}
|
||||
|
||||
//throw new \Exception(print_r($acl->rules(), TRUE));
|
||||
/**
|
||||
* Parse a rule.
|
||||
*
|
||||
* This attempts to parse an ACL rule. It is not particularly
|
||||
* fault-tolerant.
|
||||
*
|
||||
* @param int $perm The permission (ACL::READ, ACL::WRITE).
|
||||
* @param string $rule The string rule to parse.
|
||||
*
|
||||
* @return array The rule as an array.
|
||||
*/
|
||||
public static function parseRule($perm, $rule)
|
||||
{
|
||||
// This regular expression generates the following:
|
||||
//
|
||||
// array(
|
||||
// 0 => ENTIRE RULE
|
||||
// 1 => WHOLE EXPRESSION, no whitespace
|
||||
// 2 => domain compontent
|
||||
// 3 => 'rlistings', set if .rincludes is the directive
|
||||
// 4 => account name
|
||||
// 5 => :username
|
||||
// 6 => username
|
||||
// );
|
||||
$exp = '/^\s*(.r:([a-zA-Z0-9\*\-\.]+)|\.(rlistings)|([a-zA-Z0-9]+)(\:([a-zA-Z0-9]+))?)\s*$/';
|
||||
|
||||
return $acl;
|
||||
}
|
||||
$matches = array();
|
||||
preg_match($exp, $rule, $matches);
|
||||
|
||||
/**
|
||||
* Parse a rule.
|
||||
*
|
||||
* This attempts to parse an ACL rule. It is not particularly
|
||||
* fault-tolerant.
|
||||
*
|
||||
* @param int $perm The permission (ACL::READ, ACL::WRITE).
|
||||
* @param string $rule The string rule to parse.
|
||||
*
|
||||
* @return array The rule as an array.
|
||||
*/
|
||||
public static function parseRule($perm, $rule) {
|
||||
// This regular expression generates the following:
|
||||
//
|
||||
// array(
|
||||
// 0 => ENTIRE RULE
|
||||
// 1 => WHOLE EXPRESSION, no whitespace
|
||||
// 2 => domain compontent
|
||||
// 3 => 'rlistings', set if .rincludes is the directive
|
||||
// 4 => account name
|
||||
// 5 => :username
|
||||
// 6 => username
|
||||
// );
|
||||
$exp = '/^\s*(.r:([a-zA-Z0-9\*\-\.]+)|\.(rlistings)|([a-zA-Z0-9]+)(\:([a-zA-Z0-9]+))?)\s*$/';
|
||||
|
||||
$matches = array();
|
||||
preg_match($exp, $rule, $matches);
|
||||
|
||||
$entry = array('mask' => $perm);
|
||||
if (!empty($matches[2])) {
|
||||
$entry['host'] = $matches[2];
|
||||
}
|
||||
elseif (!empty($matches[3])) {
|
||||
$entry['rlistings'] = TRUE;
|
||||
}
|
||||
elseif (!empty($matches[4])) {
|
||||
$entry['account'] = $matches[4];
|
||||
if (!empty($matches[6])) {
|
||||
$entry['user'] = $matches[6];
|
||||
}
|
||||
}
|
||||
|
||||
return $entry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ACL.
|
||||
*
|
||||
* This creates an empty ACL with no permissions granted. When no
|
||||
* permissions are granted, the file is effectively private
|
||||
* (nonPublic()).
|
||||
*
|
||||
* Use add* methods to add permissions.
|
||||
*/
|
||||
public function __construct() {}
|
||||
|
||||
/**
|
||||
* Grant ACL access to an account.
|
||||
*
|
||||
* Optionally, a user may be given to further limit access.
|
||||
*
|
||||
* This is used to restrict access to a particular account and, if so
|
||||
* specified, a specific user on that account.
|
||||
*
|
||||
* If just an account is given, any user on that account will be
|
||||
* automatically granted access.
|
||||
*
|
||||
* If an account and a user is given, only that user of the account is
|
||||
* granted access.
|
||||
*
|
||||
* If $user is an array, every user in the array will be granted
|
||||
* access under the provided account. That is, for each user in the
|
||||
* array, an entry of the form `account:user` will be generated in the
|
||||
* final ACL.
|
||||
*
|
||||
* At this time there does not seem to be a way to grant global write
|
||||
* access to an object.
|
||||
*
|
||||
* @param int $perm ACL::READ, ACL::WRITE or ACL::READ_WRITE (which is the
|
||||
* same as ACL::READ|ACL::WRITE).
|
||||
* @param string $account The name of the account.
|
||||
* @param mixed $user The name of the user, or optionally an indexed array of
|
||||
* user names.
|
||||
*
|
||||
* @return \OpenStack\Storage\ObjectStorage\ACL $this for current object so
|
||||
* the method can be used in chaining.
|
||||
*/
|
||||
public function addAccount($perm, $account, $user = NULL) {
|
||||
$rule = array('account' => $account);
|
||||
|
||||
if (!empty($user)) {
|
||||
$rule['user'] = $user;
|
||||
}
|
||||
|
||||
$this->addRule($perm, $rule);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow (or deny) a hostname or host pattern.
|
||||
*
|
||||
* In current Swift implementations, only READ rules can have host
|
||||
* patterns. WRITE permissions cannot be granted to hostnames.
|
||||
*
|
||||
* Formats:
|
||||
* - Allow any host: '*'
|
||||
* - Allow exact host: 'www.example.com'
|
||||
* - Allow hosts in domain: '.example.com'
|
||||
* - Disallow exact host: '-www.example.com'
|
||||
* - Disallow hosts in domain: '-.example.com'
|
||||
*
|
||||
* Note that a simple minus sign ('-') is illegal, though it seems it
|
||||
* should be "disallow all hosts."
|
||||
*
|
||||
* @param string $perm The permission being granted. One of ACL:READ,
|
||||
* ACL::WRITE, or ACL::READ_WRITE.
|
||||
* @param string $host A host specification string as described above.
|
||||
*
|
||||
* @return \OpenStack\Storage\ObjectStorage\ACL $this for current object so
|
||||
* the method can be used in chaining.
|
||||
*/
|
||||
public function addReferrer($perm, $host = '*') {
|
||||
$this->addRule($perm, array('host' => $host));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a rule to the appropriate stack of rules.
|
||||
*
|
||||
* @param int $perm One of the predefined permission constants.
|
||||
* @param array $rule A rule array.
|
||||
*
|
||||
* @return \OpenStack\Storage\ObjectStorage\ACL $this for current object so
|
||||
* the method can be used in chaining.
|
||||
*/
|
||||
protected function addRule($perm, $rule) {
|
||||
$rule['mask'] = $perm;
|
||||
|
||||
$this->rules[] = $rule;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow hosts with READ permissions to list a container's content.
|
||||
*
|
||||
* By default, granting READ permission on a container does not grant
|
||||
* permission to list the contents of a container. Setting the
|
||||
* ACL::allowListings() permission will allow matching hosts to also list
|
||||
* the contents of a container.
|
||||
*
|
||||
* In the current Swift implementation, there is no mechanism for
|
||||
* allowing some hosts to get listings, while denying others.
|
||||
*
|
||||
* @return \OpenStack\Storage\ObjectStorage\ACL $this for current object so
|
||||
* the method can be used in chaining.
|
||||
*/
|
||||
public function allowListings() {
|
||||
|
||||
$this->rules[] = array(
|
||||
'mask' => self::READ,
|
||||
'rlistings' => TRUE,
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the rules array for this ACL.
|
||||
*
|
||||
* @return array An array of associative arrays of rules.
|
||||
*/
|
||||
public function rules() {
|
||||
return $this->rules;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate HTTP headers for this ACL.
|
||||
*
|
||||
* If this is called on an empty object, an empty set of headers is
|
||||
* returned.
|
||||
*
|
||||
* @return array Array of headers
|
||||
*/
|
||||
public function headers() {
|
||||
$headers = array();
|
||||
$readers = array();
|
||||
$writers = array();
|
||||
|
||||
// Create the rule strings. We need two copies, one for READ and
|
||||
// one for WRITE.
|
||||
foreach ($this->rules as $rule) {
|
||||
// We generate read and write rules separately so that the
|
||||
// generation logic has a chance to respond to the differences
|
||||
// allowances for READ and WRITE ACLs.
|
||||
if (self::READ & $rule['mask']) {
|
||||
$ruleStr = $this->ruleToString(self::READ, $rule);
|
||||
if (!empty($ruleStr)) {
|
||||
$readers[] = $ruleStr;
|
||||
$entry = array('mask' => $perm);
|
||||
if (!empty($matches[2])) {
|
||||
$entry['host'] = $matches[2];
|
||||
} elseif (!empty($matches[3])) {
|
||||
$entry['rlistings'] = TRUE;
|
||||
} elseif (!empty($matches[4])) {
|
||||
$entry['account'] = $matches[4];
|
||||
if (!empty($matches[6])) {
|
||||
$entry['user'] = $matches[6];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (self::WRITE & $rule['mask']) {
|
||||
$ruleStr = $this->ruleToString(self::WRITE, $rule);
|
||||
if (!empty($ruleStr)) {
|
||||
$writers[] = $ruleStr;
|
||||
|
||||
return $entry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ACL.
|
||||
*
|
||||
* This creates an empty ACL with no permissions granted. When no
|
||||
* permissions are granted, the file is effectively private
|
||||
* (nonPublic()).
|
||||
*
|
||||
* Use add* methods to add permissions.
|
||||
*/
|
||||
public function __construct() {}
|
||||
|
||||
/**
|
||||
* Grant ACL access to an account.
|
||||
*
|
||||
* Optionally, a user may be given to further limit access.
|
||||
*
|
||||
* This is used to restrict access to a particular account and, if so
|
||||
* specified, a specific user on that account.
|
||||
*
|
||||
* If just an account is given, any user on that account will be
|
||||
* automatically granted access.
|
||||
*
|
||||
* If an account and a user is given, only that user of the account is
|
||||
* granted access.
|
||||
*
|
||||
* If $user is an array, every user in the array will be granted
|
||||
* access under the provided account. That is, for each user in the
|
||||
* array, an entry of the form `account:user` will be generated in the
|
||||
* final ACL.
|
||||
*
|
||||
* At this time there does not seem to be a way to grant global write
|
||||
* access to an object.
|
||||
*
|
||||
* @param int $perm ACL::READ, ACL::WRITE or ACL::READ_WRITE (which is the
|
||||
* same as ACL::READ|ACL::WRITE).
|
||||
* @param string $account The name of the account.
|
||||
* @param mixed $user The name of the user, or optionally an indexed array of
|
||||
* user names.
|
||||
*
|
||||
* @return \OpenStack\Storage\ObjectStorage\ACL $this for current object so
|
||||
* the method can be used in chaining.
|
||||
*/
|
||||
public function addAccount($perm, $account, $user = NULL)
|
||||
{
|
||||
$rule = array('account' => $account);
|
||||
|
||||
if (!empty($user)) {
|
||||
$rule['user'] = $user;
|
||||
}
|
||||
}
|
||||
|
||||
$this->addRule($perm, $rule);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
// Create the HTTP headers.
|
||||
if (!empty($readers)) {
|
||||
$headers[self::HEADER_READ] = implode(',', $readers);
|
||||
}
|
||||
if (!empty($writers)) {
|
||||
$headers[self::HEADER_WRITE] = implode(',', $writers);
|
||||
/**
|
||||
* Allow (or deny) a hostname or host pattern.
|
||||
*
|
||||
* In current Swift implementations, only READ rules can have host
|
||||
* patterns. WRITE permissions cannot be granted to hostnames.
|
||||
*
|
||||
* Formats:
|
||||
* - Allow any host: '*'
|
||||
* - Allow exact host: 'www.example.com'
|
||||
* - Allow hosts in domain: '.example.com'
|
||||
* - Disallow exact host: '-www.example.com'
|
||||
* - Disallow hosts in domain: '-.example.com'
|
||||
*
|
||||
* Note that a simple minus sign ('-') is illegal, though it seems it
|
||||
* should be "disallow all hosts."
|
||||
*
|
||||
* @param string $perm The permission being granted. One of ACL:READ,
|
||||
* ACL::WRITE, or ACL::READ_WRITE.
|
||||
* @param string $host A host specification string as described above.
|
||||
*
|
||||
* @return \OpenStack\Storage\ObjectStorage\ACL $this for current object so
|
||||
* the method can be used in chaining.
|
||||
*/
|
||||
public function addReferrer($perm, $host = '*')
|
||||
{
|
||||
$this->addRule($perm, array('host' => $host));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
return $headers;
|
||||
}
|
||||
/**
|
||||
* Add a rule to the appropriate stack of rules.
|
||||
*
|
||||
* @param int $perm One of the predefined permission constants.
|
||||
* @param array $rule A rule array.
|
||||
*
|
||||
* @return \OpenStack\Storage\ObjectStorage\ACL $this for current object so
|
||||
* the method can be used in chaining.
|
||||
*/
|
||||
protected function addRule($perm, $rule)
|
||||
{
|
||||
$rule['mask'] = $perm;
|
||||
|
||||
/**
|
||||
* Convert a rule to a string.
|
||||
*
|
||||
* @param int $perm The permission for which to generate the rule.
|
||||
* @param array $rule A rule array.
|
||||
*/
|
||||
protected function ruleToString($perm, $rule) {
|
||||
$this->rules[] = $rule;
|
||||
|
||||
// Some rules only apply to READ.
|
||||
if (self::READ & $perm) {
|
||||
|
||||
// Host rule.
|
||||
if (!empty($rule['host'])) {
|
||||
return '.r:' . $rule['host'];
|
||||
}
|
||||
|
||||
// Listing rule.
|
||||
if (!empty($rule['rlistings'])) {
|
||||
return '.rlistings';
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
// READ and WRITE both allow account/user rules.
|
||||
if (!empty($rule['account'])) {
|
||||
/**
|
||||
* Allow hosts with READ permissions to list a container's content.
|
||||
*
|
||||
* By default, granting READ permission on a container does not grant
|
||||
* permission to list the contents of a container. Setting the
|
||||
* ACL::allowListings() permission will allow matching hosts to also list
|
||||
* the contents of a container.
|
||||
*
|
||||
* In the current Swift implementation, there is no mechanism for
|
||||
* allowing some hosts to get listings, while denying others.
|
||||
*
|
||||
* @return \OpenStack\Storage\ObjectStorage\ACL $this for current object so
|
||||
* the method can be used in chaining.
|
||||
*/
|
||||
public function allowListings()
|
||||
{
|
||||
$this->rules[] = array(
|
||||
'mask' => self::READ,
|
||||
'rlistings' => TRUE,
|
||||
);
|
||||
|
||||
// Just an account name.
|
||||
if (empty($rule['user'])) {
|
||||
return $rule['account'];
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the rules array for this ACL.
|
||||
*
|
||||
* @return array An array of associative arrays of rules.
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return $this->rules;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate HTTP headers for this ACL.
|
||||
*
|
||||
* If this is called on an empty object, an empty set of headers is
|
||||
* returned.
|
||||
*
|
||||
* @return array Array of headers
|
||||
*/
|
||||
public function headers()
|
||||
{
|
||||
$headers = array();
|
||||
$readers = array();
|
||||
$writers = array();
|
||||
|
||||
// Create the rule strings. We need two copies, one for READ and
|
||||
// one for WRITE.
|
||||
foreach ($this->rules as $rule) {
|
||||
// We generate read and write rules separately so that the
|
||||
// generation logic has a chance to respond to the differences
|
||||
// allowances for READ and WRITE ACLs.
|
||||
if (self::READ & $rule['mask']) {
|
||||
$ruleStr = $this->ruleToString(self::READ, $rule);
|
||||
if (!empty($ruleStr)) {
|
||||
$readers[] = $ruleStr;
|
||||
}
|
||||
}
|
||||
if (self::WRITE & $rule['mask']) {
|
||||
$ruleStr = $this->ruleToString(self::WRITE, $rule);
|
||||
if (!empty($ruleStr)) {
|
||||
$writers[] = $ruleStr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create the HTTP headers.
|
||||
if (!empty($readers)) {
|
||||
$headers[self::HEADER_READ] = implode(',', $readers);
|
||||
}
|
||||
if (!empty($writers)) {
|
||||
$headers[self::HEADER_WRITE] = implode(',', $writers);
|
||||
}
|
||||
|
||||
return $headers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a rule to a string.
|
||||
*
|
||||
* @param int $perm The permission for which to generate the rule.
|
||||
* @param array $rule A rule array.
|
||||
*/
|
||||
protected function ruleToString($perm, $rule)
|
||||
{
|
||||
// Some rules only apply to READ.
|
||||
if (self::READ & $perm) {
|
||||
|
||||
// Host rule.
|
||||
if (!empty($rule['host'])) {
|
||||
return '.r:' . $rule['host'];
|
||||
}
|
||||
|
||||
// Listing rule.
|
||||
if (!empty($rule['rlistings'])) {
|
||||
return '.rlistings';
|
||||
}
|
||||
}
|
||||
|
||||
// READ and WRITE both allow account/user rules.
|
||||
if (!empty($rule['account'])) {
|
||||
|
||||
// Just an account name.
|
||||
if (empty($rule['user'])) {
|
||||
return $rule['account'];
|
||||
}
|
||||
|
||||
// Account + multiple users.
|
||||
elseif (is_array($rule['user'])) {
|
||||
$buffer = array();
|
||||
foreach ($rule['user'] as $user) {
|
||||
$buffer[] = $rule['account'] . ':' . $user;
|
||||
}
|
||||
|
||||
return implode(',', $buffer);
|
||||
|
||||
}
|
||||
|
||||
// Account + one user.
|
||||
else {
|
||||
return $rule['account'] . ':' . $rule['user'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the ACL marks this private.
|
||||
*
|
||||
* This returns TRUE only if this ACL does not grant any permissions
|
||||
* at all.
|
||||
*
|
||||
* @return boolean TRUE if this is private (non-public), FALSE if any
|
||||
* permissions are granted via this ACL.
|
||||
*/
|
||||
public function isNonPublic()
|
||||
{
|
||||
return empty($this->rules);
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias of isNonPublic().
|
||||
*/
|
||||
public function isPrivate()
|
||||
{
|
||||
return $this->isNonPublic();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether this object allows public reading.
|
||||
*
|
||||
* This will return TRUE the ACL allows (a) any host to access
|
||||
* the item, and (b) it allows container listings.
|
||||
*
|
||||
* This checks whether the object allows public reading,
|
||||
* not whether it is ONLY allowing public reads.
|
||||
*
|
||||
* @see ACL::makePublic().
|
||||
*
|
||||
* @return boolean Whether or not the object allows public reading.
|
||||
*/
|
||||
public function isPublic()
|
||||
{
|
||||
$allowsAllHosts = FALSE;
|
||||
$allowsRListings = FALSE;
|
||||
foreach ($this->rules as $rule) {
|
||||
if (self::READ & $rule['mask']) {
|
||||
if (!empty($rule['rlistings'])) {
|
||||
$allowsRListings = TRUE;
|
||||
} elseif (!empty($rule['host']) && trim($rule['host']) == '*') {
|
||||
$allowsAllHosts = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $allowsAllHosts && $allowsRListings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements the magic `__toString()` PHP function.
|
||||
*
|
||||
* This allows you to `print $acl` and get back
|
||||
* a pretty string.
|
||||
*
|
||||
* @return string The ACL represented as a string.
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
$headers = $this->headers();
|
||||
|
||||
// Account + multiple users.
|
||||
elseif (is_array($rule['user'])) {
|
||||
$buffer = array();
|
||||
foreach ($rule['user'] as $user) {
|
||||
$buffer[] = $rule['account'] . ':' . $user;
|
||||
foreach ($headers as $k => $v) {
|
||||
$buffer[] = $k . ': ' . $v;
|
||||
}
|
||||
return implode(',', $buffer);
|
||||
|
||||
}
|
||||
|
||||
// Account + one user.
|
||||
else {
|
||||
return $rule['account'] . ':' . $rule['user'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the ACL marks this private.
|
||||
*
|
||||
* This returns TRUE only if this ACL does not grant any permissions
|
||||
* at all.
|
||||
*
|
||||
* @return boolean TRUE if this is private (non-public), FALSE if any
|
||||
* permissions are granted via this ACL.
|
||||
*/
|
||||
public function isNonPublic() {
|
||||
return empty($this->rules);
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias of isNonPublic().
|
||||
*/
|
||||
public function isPrivate() {
|
||||
return $this->isNonPublic();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether this object allows public reading.
|
||||
*
|
||||
* This will return TRUE the ACL allows (a) any host to access
|
||||
* the item, and (b) it allows container listings.
|
||||
*
|
||||
* This checks whether the object allows public reading,
|
||||
* not whether it is ONLY allowing public reads.
|
||||
*
|
||||
* @see ACL::makePublic().
|
||||
*
|
||||
* @return boolean Whether or not the object allows public reading.
|
||||
*/
|
||||
public function isPublic() {
|
||||
$allowsAllHosts = FALSE;
|
||||
$allowsRListings = FALSE;
|
||||
foreach ($this->rules as $rule) {
|
||||
if (self::READ & $rule['mask']) {
|
||||
if (!empty($rule['rlistings'])) {
|
||||
$allowsRListings = TRUE;
|
||||
}
|
||||
elseif(!empty($rule['host']) && trim($rule['host']) == '*') {
|
||||
$allowsAllHosts = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $allowsAllHosts && $allowsRListings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements the magic `__toString()` PHP function.
|
||||
*
|
||||
* This allows you to `print $acl` and get back
|
||||
* a pretty string.
|
||||
*
|
||||
* @return string The ACL represented as a string.
|
||||
*/
|
||||
public function __toString() {
|
||||
$headers = $this->headers();
|
||||
|
||||
$buffer = array();
|
||||
foreach ($headers as $k => $v) {
|
||||
$buffer[] = $k . ': ' . $v;
|
||||
return implode("\t", $buffer);
|
||||
}
|
||||
|
||||
return implode("\t", $buffer);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -2,17 +2,17 @@
|
||||
/* ============================================================================
|
||||
(c) Copyright 2012-2014 Hewlett-Packard Development Company, L.P.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
============================================================================ */
|
||||
/**
|
||||
* Contains exception class for ContainerNotEmptyException.
|
||||
|
@ -2,17 +2,17 @@
|
||||
/* ============================================================================
|
||||
(c) Copyright 2012-2014 Hewlett-Packard Development Company, L.P.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
============================================================================ */
|
||||
/**
|
||||
* Contains the ContentVerificationException object.
|
||||
|
@ -2,17 +2,17 @@
|
||||
/* ============================================================================
|
||||
(c) Copyright 2012-2014 Hewlett-Packard Development Company, L.P.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
============================================================================ */
|
||||
/**
|
||||
* Contains the class Object for ObjectStorage.
|
||||
@ -46,457 +46,480 @@ namespace OpenStack\Storage\ObjectStorage;
|
||||
* Likewise, a Container instance can retrieve Object instances from the
|
||||
* remote object store.
|
||||
*/
|
||||
class Object {
|
||||
class Object
|
||||
{
|
||||
const DEFAULT_CONTENT_TYPE = 'application/octet-stream';
|
||||
|
||||
const DEFAULT_CONTENT_TYPE = 'application/octet-stream';
|
||||
/**
|
||||
* The name of the object.
|
||||
*
|
||||
* This can be path-like, subject to OpenStack's definition
|
||||
* of "path-like".
|
||||
*/
|
||||
protected $name;
|
||||
|
||||
/**
|
||||
* The name of the object.
|
||||
*
|
||||
* This can be path-like, subject to OpenStack's definition
|
||||
* of "path-like".
|
||||
*/
|
||||
protected $name;
|
||||
/**
|
||||
* The content.
|
||||
*
|
||||
* Subclasses needn't use this to store an object's content,
|
||||
* as they may prefer filesystem backing.
|
||||
*/
|
||||
protected $content;
|
||||
|
||||
/**
|
||||
* The content.
|
||||
*
|
||||
* Subclasses needn't use this to store an object's content,
|
||||
* as they may prefer filesystem backing.
|
||||
*/
|
||||
protected $content;
|
||||
/**
|
||||
* The content type.
|
||||
*
|
||||
* The default type is 'application/octet-stream', which marks this as
|
||||
* a generic byte stream.
|
||||
*/
|
||||
protected $contentType = self::DEFAULT_CONTENT_TYPE;
|
||||
|
||||
/**
|
||||
* The content type.
|
||||
*
|
||||
* The default type is 'application/octet-stream', which marks this as
|
||||
* a generic byte stream.
|
||||
*/
|
||||
protected $contentType = self::DEFAULT_CONTENT_TYPE;
|
||||
/**
|
||||
* Associative array of stored metadata.
|
||||
*/
|
||||
protected $metadata = array();
|
||||
|
||||
/**
|
||||
* Associative array of stored metadata.
|
||||
*/
|
||||
protected $metadata = array();
|
||||
protected $contentEncoding;
|
||||
protected $contentDisposition;
|
||||
|
||||
protected $contentEncoding;
|
||||
protected $contentDisposition;
|
||||
/**
|
||||
* Extension mechanism for new headers.
|
||||
*/
|
||||
protected $additionalHeaders = array();
|
||||
|
||||
/**
|
||||
* Extension mechanism for new headers.
|
||||
*/
|
||||
protected $additionalHeaders = array();
|
||||
/**
|
||||
* Construct a new object for storage.
|
||||
*
|
||||
* @param string $name A name (may be pathlike) for the object.
|
||||
* @param string $content Optional content to store in this object. This is
|
||||
* the same as calling setContent().
|
||||
* @param string $type Optional content type for this content. This is the
|
||||
* same as calling setContentType().
|
||||
*/
|
||||
public function __construct($name, $content = NULL, $type = NULL)
|
||||
{
|
||||
$this->name = $name;
|
||||
|
||||
/**
|
||||
* Construct a new object for storage.
|
||||
*
|
||||
* @param string $name A name (may be pathlike) for the object.
|
||||
* @param string $content Optional content to store in this object. This is
|
||||
* the same as calling setContent().
|
||||
* @param string $type Optional content type for this content. This is the
|
||||
* same as calling setContentType().
|
||||
*/
|
||||
public function __construct($name, $content = NULL, $type = NULL) {
|
||||
$this->name = $name;
|
||||
|
||||
if (!is_null($content)) {
|
||||
$this->content = $content;
|
||||
}
|
||||
if (!empty($type)) {
|
||||
$this->contentType = $type;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the metadata.
|
||||
*
|
||||
* OpenStack allows you to specify metadata for a file. Metadata items
|
||||
* must follow these conventions:
|
||||
*
|
||||
* - names must contain only letters, numbers, and short dashes. Since
|
||||
* OpenStack normalizes the name to begin with uppercase, it is
|
||||
* suggested that you follow this convetion: Foo, not foo. Or you
|
||||
* can do your own normalizing (such as converting all to lowercase.
|
||||
* OpenStack limits the name length to 126 unicode chars.
|
||||
* - values must be encoded if they contain newlines or binary data.
|
||||
* While the exact encoding is up to you, Base-64 encoding is probably
|
||||
* your best bet. OpenStack limits the value to 256 unicode chars.
|
||||
*
|
||||
* (The docs are ambiguous -- they say chars, but they may mean
|
||||
* bytes.)
|
||||
*
|
||||
* This library does only minimal processing of metadata, and does no
|
||||
* error checking, escaping, etc. This is up to the implementor. The
|
||||
* OpenStack Swift implementation does not dictate what encoding is
|
||||
* used, though it suggests url encoding of both name and values.
|
||||
*
|
||||
* Currently, no length checking is performed in the library, nor is
|
||||
* any encoding of the data performed.
|
||||
*
|
||||
* IMPORTANT: Current versions of OpenStack Swift normalize metadata
|
||||
* names so that the name is always given an initial capital leter.
|
||||
* That is, `foo` becomes `Foo`.
|
||||
*
|
||||
* @param array $array An associative array of metadata names to values.
|
||||
*
|
||||
* @return \OpenStack\Storage\ObjectStorage\Object $this so the method can be
|
||||
* used in chaining.
|
||||
*/
|
||||
public function setMetadata(array $array) {
|
||||
$this->metadata = $array;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get any associated metadata.
|
||||
*
|
||||
* This returns an associative array of all metadata for this object.
|
||||
*
|
||||
* @return array An associative array of metadata. This may be empty.
|
||||
*/
|
||||
public function metadata() {
|
||||
return $this->metadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override (change) the name of an object.
|
||||
*
|
||||
* Note that this changes only the local copy of an object. It
|
||||
* does not rename the remote copy. In fact, changing the local name
|
||||
* and then saving it will result in a new object being created in the
|
||||
* object store.
|
||||
*
|
||||
* To copy an object:
|
||||
* @see \OpenStack\Storage\ObjectStorage\Container::copyObject().
|
||||
*
|
||||
* @param string $name A file or object name.
|
||||
*
|
||||
* @return \OpenStack\Storage\ObjectStorage\Object $this so the method can be
|
||||
* used in chaining.
|
||||
*/
|
||||
public function setName($name) {
|
||||
$this->name = $name;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name.
|
||||
*
|
||||
* Returns the name of an object. If the name has been overwritten
|
||||
* using setName(), this will return the latest (overwritten) name.
|
||||
*
|
||||
* @return string The name of the object.
|
||||
*/
|
||||
public function name() {
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the content type (MIME type) for the object.
|
||||
*
|
||||
* Object storage is, to a certain degree, content-type aware. For
|
||||
* that reason, a content type is mandatory.
|
||||
*
|
||||
* The default MIME type used is `application/octet-stream`, which is
|
||||
* the generic content type for a byte stream. Where possible, you
|
||||
* should set a more accurate content type.
|
||||
*
|
||||
* All HTTP type options are allowed. So, for example, you can add a
|
||||
* charset to a text type:
|
||||
*
|
||||
* <?php
|
||||
* $o = new Object('my.html');
|
||||
* $o->setContentType('text/html; charset=iso-8859-13');
|
||||
* ?>
|
||||
*
|
||||
* Content type is not parsed or verified locally (though it is
|
||||
* remotely). It can be dangerous, too, to allow users to specify a
|
||||
* content type.
|
||||
*
|
||||
* @param string $type A valid content type.
|
||||
*
|
||||
* @return \OpenStack\Storage\ObjectStorage\Object $this so the method can be
|
||||
* used in chaining.
|
||||
*/
|
||||
public function setContentType($type) {
|
||||
$this->contentType = $type;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the content type.
|
||||
*
|
||||
* This returns the currently set content type.
|
||||
*
|
||||
* @return string The content type, including any additional options.
|
||||
*/
|
||||
public function contentType() {
|
||||
return $this->contentType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the content for this object.
|
||||
*
|
||||
* Place the content into the object. Typically, this is string
|
||||
* content that will be stored remotely.
|
||||
*
|
||||
* PHP's string is backed by a robust system that can accomodate
|
||||
* moderately sized files. However, it is best to keep strings short
|
||||
* (<2MB, for example -- test for your own system's sweet spot).
|
||||
* Larger data may be better handled with file system entries or
|
||||
* database storage.
|
||||
*
|
||||
* Note that the OpenStack will not allow files larger than 5G, and
|
||||
* PHP will likely croak well before that marker. So use discretion.
|
||||
*
|
||||
* @param string $content The content of the object.
|
||||
* @param string $type The content type (MIME type). This can be set here for
|
||||
* convenience, or you can call setContentType() directly.
|
||||
*
|
||||
* @return \OpenStack\Storage\ObjectStorage\Object $this so the method can be
|
||||
* used in chaining.
|
||||
*/
|
||||
public function setContent($content, $type = NULL) {
|
||||
$this->content = $content;
|
||||
if (!empty($type)) {
|
||||
$this->contentType = $type;
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the content.
|
||||
*
|
||||
* Retrieve the ENTIRE content of an object.
|
||||
*
|
||||
* Note that this may be binary data (depending on what the original
|
||||
* content is). PHP strings are generally binary safe, but use this
|
||||
* with caution if you do not know what kind of data is stored in an
|
||||
* object.
|
||||
*
|
||||
* OpenStack does not do anything to validate that the content type is
|
||||
* accurate. While contentType() is intended to provide useful
|
||||
* information, poorly managed data can be written with the wrong
|
||||
* content type.
|
||||
*
|
||||
* When extending this class, you should make sure that this function
|
||||
* returns the entire contents of an object.
|
||||
*
|
||||
* @return string The content of the file.
|
||||
*/
|
||||
public function content() {
|
||||
return $this->content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the content length.
|
||||
*
|
||||
* This returns the number of bytes in a piece of content (not
|
||||
* the number of characters). Among other things, it is used to let
|
||||
* the remote object store know how big of an object to expect when
|
||||
* transmitting data.
|
||||
*
|
||||
* When extending this class, you should make sure to calculate the
|
||||
* content length appropriately.
|
||||
*
|
||||
* @return int The length of the content, in bytes.
|
||||
*/
|
||||
public function contentLength() {
|
||||
// strlen() is binary safe (or at least it seems to be).
|
||||
return strlen($this->content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate an ETag for the ObjectStorage server.
|
||||
*
|
||||
* OpenStack uses ETag to pass validation data. This generates an ETag
|
||||
* using an MD5 hash of the content.
|
||||
*
|
||||
* When extending this class, generate an ETag by creating an MD5 of
|
||||
* the entire object's content (but not the metadata or name).
|
||||
*
|
||||
* @return string An MD5 value as a string of 32 hex digits (0-9a-f).
|
||||
*/
|
||||
public function eTag() {
|
||||
return md5($this->content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the encoding for a file.
|
||||
*
|
||||
* You can use content encoding on compressed content to indicate to
|
||||
* the receiving agent that a file is encoded using a specific
|
||||
* compression type.
|
||||
*
|
||||
* Typical compression types are 'gzip', 'zip', and 'compress', though
|
||||
* many others exist.
|
||||
*
|
||||
* This allows you, for example, to save a zipped file, yet preserve
|
||||
* its underlying content type. For example, for a gzipped text/plain
|
||||
* file, you can set the content type to "text/plain" and the encoding
|
||||
* to "gzip". This allows many user agents to receive the compressed
|
||||
* data and automatically decompress them and display them correctly.
|
||||
*
|
||||
* @param string $encoding A valid encoding type.
|
||||
*
|
||||
* @return \OpenStack\Storage\ObjectStorage\Object $this so the method can be
|
||||
* used in chaining.
|
||||
*/
|
||||
public function setEncoding($encoding) {
|
||||
$this->contentEncoding = $encoding;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the encoding (if any) for this object.
|
||||
*
|
||||
* Encoding is used to indicate how a file was encoded or compressed.
|
||||
* See setEncoding() for more information.
|
||||
*
|
||||
* @return string The encoding type.
|
||||
*/
|
||||
public function encoding() {
|
||||
return $this->contentEncoding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the content disposition.
|
||||
*
|
||||
* This makes it possible to have the file act like a download (in a
|
||||
* browser or similar agent), even if the MIME type normally triggers
|
||||
* a display.
|
||||
*
|
||||
* The typical value for this is:
|
||||
*
|
||||
* <?php
|
||||
* $object->setDisposition('attachment; filename=foo.png');
|
||||
* ?>
|
||||
*
|
||||
* A disposition string should not include any newline characters or
|
||||
* binary data.
|
||||
*
|
||||
* @param string $disposition A valid disposition declaration. These are
|
||||
* defined in various HTTP specifications.
|
||||
*
|
||||
* @return \OpenStack\Storage\ObjectStorage\Object $this so the method can be
|
||||
* used in chaining.
|
||||
*/
|
||||
public function setDisposition($disposition) {
|
||||
$this->contentDisposition = $disposition;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current disposition string, if any.
|
||||
*
|
||||
* See setDisposition() for discussion.
|
||||
*
|
||||
* @return string The disposition string, or NULL if none is set.
|
||||
*/
|
||||
public function disposition() {
|
||||
return $this->contentDisposition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set additional headers for storage.
|
||||
*
|
||||
* EXPERT: You will need to understand OpenStack internals to use this
|
||||
* effectively.
|
||||
*
|
||||
* Headers set here will be added to the HTTP request during save
|
||||
* operations. They are not merged into existing headers until
|
||||
* save-time.
|
||||
*
|
||||
* This provides a mechanism for adding extension headers. CORS
|
||||
* headers and possibly others are stored by Swift, but have no
|
||||
* semantic value to Swift or to popular user agents.
|
||||
*
|
||||
* There are a few things to note about this mechanism:
|
||||
*
|
||||
* - Existing headers cannot be overwritten. Only new headers can be
|
||||
* added.
|
||||
* - Headers are not merged. They are simply sent to the remote
|
||||
* server. A new object must be retrieved from the server before
|
||||
* these headers will be accessible.
|
||||
* - Swift only stores certain headers. If you supply an unrecognized
|
||||
* header to Swift, it may simply ignore it.
|
||||
* - The RemoteObject::headers() method provides access to all of the
|
||||
* headers returned from Swift.
|
||||
* - Headers are merged in as they are, with no cleaning, encoding, or
|
||||
* checking. You must ensure that the headers are in the proper
|
||||
* format.
|
||||
*
|
||||
* @param array $headers An associative array where each name is an HTTP
|
||||
* header name, and each value is the HTTP header value. No encoding or
|
||||
* escaping is done.
|
||||
*
|
||||
* @return \OpenStack\Storage\ObjectStorage\Object $this so the method can be
|
||||
* used in chaining.
|
||||
*/
|
||||
public function setAdditionalHeaders($headers) {
|
||||
$this->additionalHeaders = $headers;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return additional headers.
|
||||
*
|
||||
* Headers here have likely not been stored remotely until
|
||||
* Container::save() is called on the object.
|
||||
*/
|
||||
public function additionalHeaders() {
|
||||
return $this->additionalHeaders;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove headers.
|
||||
*
|
||||
* This takes an array of header names, and removes
|
||||
* any matching headers. Typically, only headers set
|
||||
* by setAdditionalHeaders() are removed from an Object.
|
||||
* (RemoteObject works differently).
|
||||
*
|
||||
* Many headers are generated automatically, such as
|
||||
* Content-Type and Content-Length. Removing these
|
||||
* will simply result in their being regenerated.
|
||||
*
|
||||
* @param array $keys The header names to be removed.
|
||||
*
|
||||
* @return \OpenStack\Storage\ObjectStorage\Object $this for the current
|
||||
* object so it can be used in chaining methods.
|
||||
*/
|
||||
public function removeHeaders($keys) {
|
||||
foreach ($keys as $k) {
|
||||
unset($this->additionalHeaders[$k]);
|
||||
if (!is_null($content)) {
|
||||
$this->content = $content;
|
||||
}
|
||||
if (!empty($type)) {
|
||||
$this->contentType = $type;
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
/**
|
||||
* Set the metadata.
|
||||
*
|
||||
* OpenStack allows you to specify metadata for a file. Metadata items
|
||||
* must follow these conventions:
|
||||
*
|
||||
* - names must contain only letters, numbers, and short dashes. Since
|
||||
* OpenStack normalizes the name to begin with uppercase, it is
|
||||
* suggested that you follow this convetion: Foo, not foo. Or you
|
||||
* can do your own normalizing (such as converting all to lowercase.
|
||||
* OpenStack limits the name length to 126 unicode chars.
|
||||
* - values must be encoded if they contain newlines or binary data.
|
||||
* While the exact encoding is up to you, Base-64 encoding is probably
|
||||
* your best bet. OpenStack limits the value to 256 unicode chars.
|
||||
*
|
||||
* (The docs are ambiguous -- they say chars, but they may mean
|
||||
* bytes.)
|
||||
*
|
||||
* This library does only minimal processing of metadata, and does no
|
||||
* error checking, escaping, etc. This is up to the implementor. The
|
||||
* OpenStack Swift implementation does not dictate what encoding is
|
||||
* used, though it suggests url encoding of both name and values.
|
||||
*
|
||||
* Currently, no length checking is performed in the library, nor is
|
||||
* any encoding of the data performed.
|
||||
*
|
||||
* IMPORTANT: Current versions of OpenStack Swift normalize metadata
|
||||
* names so that the name is always given an initial capital leter.
|
||||
* That is, `foo` becomes `Foo`.
|
||||
*
|
||||
* @param array $array An associative array of metadata names to values.
|
||||
*
|
||||
* @return \OpenStack\Storage\ObjectStorage\Object $this so the method can be
|
||||
* used in chaining.
|
||||
*/
|
||||
public function setMetadata(array $array)
|
||||
{
|
||||
$this->metadata = $array;
|
||||
|
||||
/**
|
||||
* This object should be transmitted in chunks.
|
||||
*
|
||||
* Indicates whether or not this object should be transmitted as
|
||||
* chunked data (in HTTP).
|
||||
*
|
||||
* This should be used when (a) the file size is large, or (b) the
|
||||
* exact size of the file is unknown.
|
||||
*
|
||||
* If this returns TRUE, it does not guarantee that the data
|
||||
* will be transmitted in chunks. But it recommends that the
|
||||
* underlying transport layer use chunked encoding.
|
||||
*
|
||||
* The contentLength() method is not called for chunked transfers. So
|
||||
* if this returns TRUE, contentLength() is ignored.
|
||||
*
|
||||
* @return boolean TRUE to recommend chunked transfer, FALSE otherwise.
|
||||
*/
|
||||
public function isChunked() {
|
||||
// Currently, this value is hard-coded. The default Object
|
||||
// implementation does not get chunked.
|
||||
return FALSE;
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get any associated metadata.
|
||||
*
|
||||
* This returns an associative array of all metadata for this object.
|
||||
*
|
||||
* @return array An associative array of metadata. This may be empty.
|
||||
*/
|
||||
public function metadata()
|
||||
{
|
||||
return $this->metadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override (change) the name of an object.
|
||||
*
|
||||
* Note that this changes only the local copy of an object. It
|
||||
* does not rename the remote copy. In fact, changing the local name
|
||||
* and then saving it will result in a new object being created in the
|
||||
* object store.
|
||||
*
|
||||
* To copy an object:
|
||||
* @see \OpenStack\Storage\ObjectStorage\Container::copyObject().
|
||||
*
|
||||
* @param string $name A file or object name.
|
||||
*
|
||||
* @return \OpenStack\Storage\ObjectStorage\Object $this so the method can be
|
||||
* used in chaining.
|
||||
*/
|
||||
public function setName($name)
|
||||
{
|
||||
$this->name = $name;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name.
|
||||
*
|
||||
* Returns the name of an object. If the name has been overwritten
|
||||
* using setName(), this will return the latest (overwritten) name.
|
||||
*
|
||||
* @return string The name of the object.
|
||||
*/
|
||||
public function name()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the content type (MIME type) for the object.
|
||||
*
|
||||
* Object storage is, to a certain degree, content-type aware. For
|
||||
* that reason, a content type is mandatory.
|
||||
*
|
||||
* The default MIME type used is `application/octet-stream`, which is
|
||||
* the generic content type for a byte stream. Where possible, you
|
||||
* should set a more accurate content type.
|
||||
*
|
||||
* All HTTP type options are allowed. So, for example, you can add a
|
||||
* charset to a text type:
|
||||
*
|
||||
* <?php
|
||||
* $o = new Object('my.html');
|
||||
* $o->setContentType('text/html; charset=iso-8859-13');
|
||||
* ?>
|
||||
*
|
||||
* Content type is not parsed or verified locally (though it is
|
||||
* remotely). It can be dangerous, too, to allow users to specify a
|
||||
* content type.
|
||||
*
|
||||
* @param string $type A valid content type.
|
||||
*
|
||||
* @return \OpenStack\Storage\ObjectStorage\Object $this so the method can be
|
||||
* used in chaining.
|
||||
*/
|
||||
public function setContentType($type)
|
||||
{
|
||||
$this->contentType = $type;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the content type.
|
||||
*
|
||||
* This returns the currently set content type.
|
||||
*
|
||||
* @return string The content type, including any additional options.
|
||||
*/
|
||||
public function contentType()
|
||||
{
|
||||
return $this->contentType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the content for this object.
|
||||
*
|
||||
* Place the content into the object. Typically, this is string
|
||||
* content that will be stored remotely.
|
||||
*
|
||||
* PHP's string is backed by a robust system that can accomodate
|
||||
* moderately sized files. However, it is best to keep strings short
|
||||
* (<2MB, for example -- test for your own system's sweet spot).
|
||||
* Larger data may be better handled with file system entries or
|
||||
* database storage.
|
||||
*
|
||||
* Note that the OpenStack will not allow files larger than 5G, and
|
||||
* PHP will likely croak well before that marker. So use discretion.
|
||||
*
|
||||
* @param string $content The content of the object.
|
||||
* @param string $type The content type (MIME type). This can be set here for
|
||||
* convenience, or you can call setContentType() directly.
|
||||
*
|
||||
* @return \OpenStack\Storage\ObjectStorage\Object $this so the method can be
|
||||
* used in chaining.
|
||||
*/
|
||||
public function setContent($content, $type = NULL)
|
||||
{
|
||||
$this->content = $content;
|
||||
if (!empty($type)) {
|
||||
$this->contentType = $type;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the content.
|
||||
*
|
||||
* Retrieve the ENTIRE content of an object.
|
||||
*
|
||||
* Note that this may be binary data (depending on what the original
|
||||
* content is). PHP strings are generally binary safe, but use this
|
||||
* with caution if you do not know what kind of data is stored in an
|
||||
* object.
|
||||
*
|
||||
* OpenStack does not do anything to validate that the content type is
|
||||
* accurate. While contentType() is intended to provide useful
|
||||
* information, poorly managed data can be written with the wrong
|
||||
* content type.
|
||||
*
|
||||
* When extending this class, you should make sure that this function
|
||||
* returns the entire contents of an object.
|
||||
*
|
||||
* @return string The content of the file.
|
||||
*/
|
||||
public function content()
|
||||
{
|
||||
return $this->content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the content length.
|
||||
*
|
||||
* This returns the number of bytes in a piece of content (not
|
||||
* the number of characters). Among other things, it is used to let
|
||||
* the remote object store know how big of an object to expect when
|
||||
* transmitting data.
|
||||
*
|
||||
* When extending this class, you should make sure to calculate the
|
||||
* content length appropriately.
|
||||
*
|
||||
* @return int The length of the content, in bytes.
|
||||
*/
|
||||
public function contentLength()
|
||||
{
|
||||
// strlen() is binary safe (or at least it seems to be).
|
||||
return strlen($this->content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate an ETag for the ObjectStorage server.
|
||||
*
|
||||
* OpenStack uses ETag to pass validation data. This generates an ETag
|
||||
* using an MD5 hash of the content.
|
||||
*
|
||||
* When extending this class, generate an ETag by creating an MD5 of
|
||||
* the entire object's content (but not the metadata or name).
|
||||
*
|
||||
* @return string An MD5 value as a string of 32 hex digits (0-9a-f).
|
||||
*/
|
||||
public function eTag()
|
||||
{
|
||||
return md5($this->content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the encoding for a file.
|
||||
*
|
||||
* You can use content encoding on compressed content to indicate to
|
||||
* the receiving agent that a file is encoded using a specific
|
||||
* compression type.
|
||||
*
|
||||
* Typical compression types are 'gzip', 'zip', and 'compress', though
|
||||
* many others exist.
|
||||
*
|
||||
* This allows you, for example, to save a zipped file, yet preserve
|
||||
* its underlying content type. For example, for a gzipped text/plain
|
||||
* file, you can set the content type to "text/plain" and the encoding
|
||||
* to "gzip". This allows many user agents to receive the compressed
|
||||
* data and automatically decompress them and display them correctly.
|
||||
*
|
||||
* @param string $encoding A valid encoding type.
|
||||
*
|
||||
* @return \OpenStack\Storage\ObjectStorage\Object $this so the method can be
|
||||
* used in chaining.
|
||||
*/
|
||||
public function setEncoding($encoding)
|
||||
{
|
||||
$this->contentEncoding = $encoding;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the encoding (if any) for this object.
|
||||
*
|
||||
* Encoding is used to indicate how a file was encoded or compressed.
|
||||
* See setEncoding() for more information.
|
||||
*
|
||||
* @return string The encoding type.
|
||||
*/
|
||||
public function encoding()
|
||||
{
|
||||
return $this->contentEncoding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the content disposition.
|
||||
*
|
||||
* This makes it possible to have the file act like a download (in a
|
||||
* browser or similar agent), even if the MIME type normally triggers
|
||||
* a display.
|
||||
*
|
||||
* The typical value for this is:
|
||||
*
|
||||
* <?php
|
||||
* $object->setDisposition('attachment; filename=foo.png');
|
||||
* ?>
|
||||
*
|
||||
* A disposition string should not include any newline characters or
|
||||
* binary data.
|
||||
*
|
||||
* @param string $disposition A valid disposition declaration. These are
|
||||
* defined in various HTTP specifications.
|
||||
*
|
||||
* @return \OpenStack\Storage\ObjectStorage\Object $this so the method can be
|
||||
* used in chaining.
|
||||
*/
|
||||
public function setDisposition($disposition)
|
||||
{
|
||||
$this->contentDisposition = $disposition;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current disposition string, if any.
|
||||
*
|
||||
* See setDisposition() for discussion.
|
||||
*
|
||||
* @return string The disposition string, or NULL if none is set.
|
||||
*/
|
||||
public function disposition()
|
||||
{
|
||||
return $this->contentDisposition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set additional headers for storage.
|
||||
*
|
||||
* EXPERT: You will need to understand OpenStack internals to use this
|
||||
* effectively.
|
||||
*
|
||||
* Headers set here will be added to the HTTP request during save
|
||||
* operations. They are not merged into existing headers until
|
||||
* save-time.
|
||||
*
|
||||
* This provides a mechanism for adding extension headers. CORS
|
||||
* headers and possibly others are stored by Swift, but have no
|
||||
* semantic value to Swift or to popular user agents.
|
||||
*
|
||||
* There are a few things to note about this mechanism:
|
||||
*
|
||||
* - Existing headers cannot be overwritten. Only new headers can be
|
||||
* added.
|
||||
* - Headers are not merged. They are simply sent to the remote
|
||||
* server. A new object must be retrieved from the server before
|
||||
* these headers will be accessible.
|
||||
* - Swift only stores certain headers. If you supply an unrecognized
|
||||
* header to Swift, it may simply ignore it.
|
||||
* - The RemoteObject::headers() method provides access to all of the
|
||||
* headers returned from Swift.
|
||||
* - Headers are merged in as they are, with no cleaning, encoding, or
|
||||
* checking. You must ensure that the headers are in the proper
|
||||
* format.
|
||||
*
|
||||
* @param array $headers An associative array where each name is an HTTP
|
||||
* header name, and each value is the HTTP header value. No encoding or
|
||||
* escaping is done.
|
||||
*
|
||||
* @return \OpenStack\Storage\ObjectStorage\Object $this so the method can be
|
||||
* used in chaining.
|
||||
*/
|
||||
public function setAdditionalHeaders($headers)
|
||||
{
|
||||
$this->additionalHeaders = $headers;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return additional headers.
|
||||
*
|
||||
* Headers here have likely not been stored remotely until
|
||||
* Container::save() is called on the object.
|
||||
*/
|
||||
public function additionalHeaders()
|
||||
{
|
||||
return $this->additionalHeaders;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove headers.
|
||||
*
|
||||
* This takes an array of header names, and removes
|
||||
* any matching headers. Typically, only headers set
|
||||
* by setAdditionalHeaders() are removed from an Object.
|
||||
* (RemoteObject works differently).
|
||||
*
|
||||
* Many headers are generated automatically, such as
|
||||
* Content-Type and Content-Length. Removing these
|
||||
* will simply result in their being regenerated.
|
||||
*
|
||||
* @param array $keys The header names to be removed.
|
||||
*
|
||||
* @return \OpenStack\Storage\ObjectStorage\Object $this for the current
|
||||
* object so it can be used in chaining methods.
|
||||
*/
|
||||
public function removeHeaders($keys)
|
||||
{
|
||||
foreach ($keys as $k) {
|
||||
unset($this->additionalHeaders[$k]);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* This object should be transmitted in chunks.
|
||||
*
|
||||
* Indicates whether or not this object should be transmitted as
|
||||
* chunked data (in HTTP).
|
||||
*
|
||||
* This should be used when (a) the file size is large, or (b) the
|
||||
* exact size of the file is unknown.
|
||||
*
|
||||
* If this returns TRUE, it does not guarantee that the data
|
||||
* will be transmitted in chunks. But it recommends that the
|
||||
* underlying transport layer use chunked encoding.
|
||||
*
|
||||
* The contentLength() method is not called for chunked transfers. So
|
||||
* if this returns TRUE, contentLength() is ignored.
|
||||
*
|
||||
* @return boolean TRUE to recommend chunked transfer, FALSE otherwise.
|
||||
*/
|
||||
public function isChunked()
|
||||
{
|
||||
// Currently, this value is hard-coded. The default Object
|
||||
// implementation does not get chunked.
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
@ -2,17 +2,17 @@
|
||||
/* ============================================================================
|
||||
(c) Copyright 2012-2014 Hewlett-Packard Development Company, L.P.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
============================================================================ */
|
||||
|
||||
namespace OpenStack\Storage\ObjectStorage;
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -2,17 +2,17 @@
|
||||
/* ============================================================================
|
||||
(c) Copyright 2012-2014 Hewlett-Packard Development Company, L.P.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
============================================================================ */
|
||||
/**
|
||||
* Contains the stream wrapper for `swiftfs://` URLs.
|
||||
@ -71,144 +71,145 @@ use \OpenStack\Storage\ObjectStorage;
|
||||
*
|
||||
* @see http://us3.php.net/manual/en/class.streamwrapper.php
|
||||
*/
|
||||
class StreamWrapperFS extends StreamWrapper {
|
||||
class StreamWrapperFS extends StreamWrapper
|
||||
{
|
||||
const DEFAULT_SCHEME = 'swiftfs';
|
||||
protected $schemeName = self::DEFAULT_SCHEME;
|
||||
|
||||
const DEFAULT_SCHEME = 'swiftfs';
|
||||
protected $schemeName = self::DEFAULT_SCHEME;
|
||||
/**
|
||||
* Fake a make a dir.
|
||||
*
|
||||
* ObjectStorage has pathy objects not directories. If no objects with a path
|
||||
* prefix exist we can pass creating a directory. If objects with a path
|
||||
* prefix exist adding the directory will fail.
|
||||
*/
|
||||
public function mkdir($uri, $mode, $options)
|
||||
{
|
||||
return ($this->cxt('swiftfs_fake_isdir_true', FALSE) || !($this->testDirectoryExists($uri)));
|
||||
|
||||
/**
|
||||
* Fake a make a dir.
|
||||
*
|
||||
* ObjectStorage has pathy objects not directories. If no objects with a path
|
||||
* prefix exist we can pass creating a directory. If objects with a path
|
||||
* prefix exist adding the directory will fail.
|
||||
*/
|
||||
public function mkdir($uri, $mode, $options) {
|
||||
|
||||
return ($this->cxt('swiftfs_fake_isdir_true', FALSE) || !($this->testDirectoryExists($uri)));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Fake Remove a directory.
|
||||
*
|
||||
* ObjectStorage has pathy objects not directories. If no objects with a path
|
||||
* prefix exist we can pass removing it. If objects with a path prefix exist
|
||||
* removing the directory will fail.
|
||||
*/
|
||||
public function rmdir($path, $options) {
|
||||
|
||||
return !($this->testDirectoryExists($path));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @see stream_stat().
|
||||
*/
|
||||
public function url_stat($path, $flags) {
|
||||
$stat = parent::url_stat($path, $flags);
|
||||
|
||||
// If the file stat setup returned anything return it.
|
||||
if ($stat) {
|
||||
return $stat;
|
||||
}
|
||||
// When FALSE is returned there is no file to stat. So, we attempt to handle
|
||||
// it like a directory.
|
||||
else {
|
||||
if ($this->cxt('swiftfs_fake_isdir_true', FALSE) || $this->testDirectoryExists($path)) {
|
||||
// The directory prefix exists. Fake the directory file permissions.
|
||||
return $this->fakeStat(TRUE);
|
||||
}
|
||||
else {
|
||||
// The directory does not exist as a prefix.
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
// INTERNAL METHODS
|
||||
// All methods beneath this line are not part of the Stream API.
|
||||
///////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Test if a path prefix (directory like) esits.
|
||||
*
|
||||
* ObjectStorage has pathy objects not directories. If objects exist with a
|
||||
* path prefix we can consider that the directory exists. For example, if
|
||||
* we have an object at foo/bar/baz.txt and test the existance of the
|
||||
* directory foo/bar/ we sould see it.
|
||||
*
|
||||
* @param string $path The directory path to test.
|
||||
*
|
||||
* @return boolean TRUE if the directory prefix exists and FALSE otherwise.
|
||||
*/
|
||||
protected function testDirectoryExists($path) {
|
||||
$url = $this->parseUrl($path);
|
||||
|
||||
if (empty($url['host'])) {
|
||||
trigger_error('Container name is required.' , E_USER_WARNING);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
try {
|
||||
$this->initializeObjectStorage();
|
||||
$container = $this->store->container($url['host']);
|
||||
/**
|
||||
* Fake Remove a directory.
|
||||
*
|
||||
* ObjectStorage has pathy objects not directories. If no objects with a path
|
||||
* prefix exist we can pass removing it. If objects with a path prefix exist
|
||||
* removing the directory will fail.
|
||||
*/
|
||||
public function rmdir($path, $options)
|
||||
{
|
||||
return !($this->testDirectoryExists($path));
|
||||
|
||||
if (empty($url['path'])) {
|
||||
$this->dirPrefix = '';
|
||||
}
|
||||
else {
|
||||
$this->dirPrefix = $url['path'];
|
||||
}
|
||||
|
||||
$sep = '/';
|
||||
|
||||
|
||||
$dirListing = $container->objectsWithPrefix($this->dirPrefix, $sep);
|
||||
|
||||
return !empty($dirListing);
|
||||
}
|
||||
catch (\OpenStack\Exception $e) {
|
||||
trigger_error('Path could not be opened: ' . $e->getMessage(), E_USER_WARNING);
|
||||
return FALSE;
|
||||
|
||||
/**
|
||||
* @see stream_stat().
|
||||
*/
|
||||
public function url_stat($path, $flags)
|
||||
{
|
||||
$stat = parent::url_stat($path, $flags);
|
||||
|
||||
// If the file stat setup returned anything return it.
|
||||
if ($stat) {
|
||||
return $stat;
|
||||
}
|
||||
// When FALSE is returned there is no file to stat. So, we attempt to handle
|
||||
// it like a directory.
|
||||
else {
|
||||
if ($this->cxt('swiftfs_fake_isdir_true', FALSE) || $this->testDirectoryExists($path)) {
|
||||
// The directory prefix exists. Fake the directory file permissions.
|
||||
return $this->fakeStat(TRUE);
|
||||
} else {
|
||||
// The directory does not exist as a prefix.
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fake stat data.
|
||||
*
|
||||
* Under certain conditions we have to return totally trumped-up
|
||||
* stats. This generates those.
|
||||
*/
|
||||
protected function fakeStat($dir = FALSE) {
|
||||
///////////////////////////////////////////////////////////////////
|
||||
// INTERNAL METHODS
|
||||
// All methods beneath this line are not part of the Stream API.
|
||||
///////////////////////////////////////////////////////////////////
|
||||
|
||||
$request_time = time();
|
||||
/**
|
||||
* Test if a path prefix (directory like) esits.
|
||||
*
|
||||
* ObjectStorage has pathy objects not directories. If objects exist with a
|
||||
* path prefix we can consider that the directory exists. For example, if
|
||||
* we have an object at foo/bar/baz.txt and test the existance of the
|
||||
* directory foo/bar/ we sould see it.
|
||||
*
|
||||
* @param string $path The directory path to test.
|
||||
*
|
||||
* @return boolean TRUE if the directory prefix exists and FALSE otherwise.
|
||||
*/
|
||||
protected function testDirectoryExists($path)
|
||||
{
|
||||
$url = $this->parseUrl($path);
|
||||
|
||||
// Set inode type to directory or file.
|
||||
$type = $dir ? 040000 : 0100000;
|
||||
// Fake world-readible
|
||||
$mode = $type + $this->cxt('swiftfs_fake_stat_mode', 0777);
|
||||
if (empty($url['host'])) {
|
||||
trigger_error('Container name is required.' , E_USER_WARNING);
|
||||
|
||||
$values = array(
|
||||
'dev' => 0,
|
||||
'ino' => 0,
|
||||
'mode' => $mode,
|
||||
'nlink' => 0,
|
||||
'uid' => posix_getuid(),
|
||||
'gid' => posix_getgid(),
|
||||
'rdev' => 0,
|
||||
'size' => 0,
|
||||
'atime' => $request_time,
|
||||
'mtime' => $request_time,
|
||||
'ctime' => $request_time,
|
||||
'blksize' => -1,
|
||||
'blocks' => -1,
|
||||
);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$final = array_values($values) + $values;
|
||||
try {
|
||||
$this->initializeObjectStorage();
|
||||
$container = $this->store->container($url['host']);
|
||||
|
||||
return $final;
|
||||
}
|
||||
if (empty($url['path'])) {
|
||||
$this->dirPrefix = '';
|
||||
} else {
|
||||
$this->dirPrefix = $url['path'];
|
||||
}
|
||||
|
||||
$sep = '/';
|
||||
|
||||
|
||||
$dirListing = $container->objectsWithPrefix($this->dirPrefix, $sep);
|
||||
|
||||
return !empty($dirListing);
|
||||
} catch (\OpenStack\Exception $e) {
|
||||
trigger_error('Path could not be opened: ' . $e->getMessage(), E_USER_WARNING);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fake stat data.
|
||||
*
|
||||
* Under certain conditions we have to return totally trumped-up
|
||||
* stats. This generates those.
|
||||
*/
|
||||
protected function fakeStat($dir = FALSE)
|
||||
{
|
||||
$request_time = time();
|
||||
|
||||
// Set inode type to directory or file.
|
||||
$type = $dir ? 040000 : 0100000;
|
||||
// Fake world-readible
|
||||
$mode = $type + $this->cxt('swiftfs_fake_stat_mode', 0777);
|
||||
|
||||
$values = array(
|
||||
'dev' => 0,
|
||||
'ino' => 0,
|
||||
'mode' => $mode,
|
||||
'nlink' => 0,
|
||||
'uid' => posix_getuid(),
|
||||
'gid' => posix_getgid(),
|
||||
'rdev' => 0,
|
||||
'size' => 0,
|
||||
'atime' => $request_time,
|
||||
'mtime' => $request_time,
|
||||
'ctime' => $request_time,
|
||||
'blksize' => -1,
|
||||
'blocks' => -1,
|
||||
);
|
||||
|
||||
$final = array_values($values) + $values;
|
||||
|
||||
return $final;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -2,17 +2,17 @@
|
||||
/* ============================================================================
|
||||
(c) Copyright 2012-2014 Hewlett-Packard Development Company, L.P.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
============================================================================ */
|
||||
/**
|
||||
* Contains the Subdir class.
|
||||
@ -28,48 +28,50 @@ namespace OpenStack\Storage\ObjectStorage;
|
||||
*
|
||||
* Subdirs are used for things that are directory-like.
|
||||
*/
|
||||
class Subdir {
|
||||
class Subdir
|
||||
{
|
||||
/**
|
||||
* @var string The path string that this subdir describes
|
||||
*/
|
||||
protected $path;
|
||||
|
||||
/**
|
||||
* @var string The path string that this subdir describes
|
||||
*/
|
||||
protected $path;
|
||||
/**
|
||||
* @var string The delimiter used in this path
|
||||
*/
|
||||
protected $delimiter;
|
||||
|
||||
/**
|
||||
* @var string The delimiter used in this path
|
||||
*/
|
||||
protected $delimiter;
|
||||
/**
|
||||
* Create a new subdirectory.
|
||||
*
|
||||
* This represents a remote response's tag for a subdirectory.
|
||||
*
|
||||
* @param string $path The path string that this subdir describes.
|
||||
* @param string $delimiter The delimiter used in this path.
|
||||
*/
|
||||
public function __construct($path, $delimiter = '/')
|
||||
{
|
||||
$this->path = $path;
|
||||
$this->delimiter = $delimiter;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a new subdirectory.
|
||||
*
|
||||
* This represents a remote response's tag for a subdirectory.
|
||||
*
|
||||
* @param string $path The path string that this subdir describes.
|
||||
* @param string $delimiter The delimiter used in this path.
|
||||
*/
|
||||
public function __construct($path, $delimiter = '/') {
|
||||
$this->path = $path;
|
||||
$this->delimiter = $delimiter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the path.
|
||||
*
|
||||
* The path is delimited using the string returned by delimiter().
|
||||
*
|
||||
* @return string The path
|
||||
*/
|
||||
public function path() {
|
||||
return $this->path;
|
||||
}
|
||||
/**
|
||||
* Get the delimiter used by the server.
|
||||
*
|
||||
* @return string The value used as a delimiter.
|
||||
*/
|
||||
public function delimiter() {
|
||||
return $this->delimiter;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Get the path.
|
||||
*
|
||||
* The path is delimited using the string returned by delimiter().
|
||||
*
|
||||
* @return string The path
|
||||
*/
|
||||
public function path()
|
||||
{
|
||||
return $this->path;
|
||||
}
|
||||
/**
|
||||
* Get the delimiter used by the server.
|
||||
*
|
||||
* @return string The value used as a delimiter.
|
||||
*/
|
||||
public function delimiter()
|
||||
{
|
||||
return $this->delimiter;
|
||||
}
|
||||
}
|
||||
|
@ -2,17 +2,17 @@
|
||||
/* ============================================================================
|
||||
(c) Copyright 2012-2014 Hewlett-Packard Development Company, L.P.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
============================================================================ */
|
||||
/**
|
||||
* The authorization exception.
|
||||
|
@ -2,17 +2,17 @@
|
||||
/* ============================================================================
|
||||
(c) Copyright 2012-2014 Hewlett-Packard Development Company, L.P.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
============================================================================ */
|
||||
/**
|
||||
* This file contains the interface for transporters.
|
||||
@ -32,94 +32,93 @@ namespace OpenStack\Transport;
|
||||
* HTTP/HTTPS, and perhaps SPDY some day. The interface reflects this.
|
||||
* it is not designed as a protocol-neutral transport layer
|
||||
*/
|
||||
interface ClientInterface {
|
||||
interface ClientInterface
|
||||
{
|
||||
const HTTP_USER_AGENT = 'OpenStack-PHP/1.0';
|
||||
|
||||
const HTTP_USER_AGENT = 'OpenStack-PHP/1.0';
|
||||
/**
|
||||
* Setup for the HTTP Client.
|
||||
*
|
||||
* @param array $options Options for the HTTP Client including:
|
||||
* - headers (array) A key/value mapping of default headers for each request.
|
||||
* - proxy (string) A proxy specified as a URI.
|
||||
* - debug (bool) True if debug output should be displayed.
|
||||
* - timeout (int) The timeout, in seconds, a request should wait before
|
||||
* timing out.
|
||||
* - ssl_verify (bool|string) True, the default, verifies the SSL certificate,
|
||||
* FALSE disables verification, and a string is the path to a CA to verify
|
||||
* against.
|
||||
*/
|
||||
public function __construct(array $options = []);
|
||||
|
||||
/**
|
||||
* Setup for the HTTP Client.
|
||||
*
|
||||
* @param array $options Options for the HTTP Client including:
|
||||
* - headers (array) A key/value mapping of default headers for each request.
|
||||
* - proxy (string) A proxy specified as a URI.
|
||||
* - debug (bool) True if debug output should be displayed.
|
||||
* - timeout (int) The timeout, in seconds, a request should wait before
|
||||
* timing out.
|
||||
* - ssl_verify (bool|string) True, the default, verifies the SSL certificate,
|
||||
* FALSE disables verification, and a string is the path to a CA to verify
|
||||
* against.
|
||||
*/
|
||||
public function __construct(array $options = []);
|
||||
/**
|
||||
* Perform a request.
|
||||
*
|
||||
* Invoking this method causes a single request to be relayed over the
|
||||
* transporter. The transporter MUST be capable of handling multiple
|
||||
* invocations of a doRequest() call.
|
||||
*
|
||||
* @param string $uri The target URI.
|
||||
* @param string $method The method to be sent.
|
||||
* @param array $headers An array of name/value header pairs.
|
||||
* @param string $body The string containing the request body.
|
||||
*
|
||||
* @return \OpenStack\Transport\ResponseInterface The response. The response
|
||||
* is implicit rather than explicit. The interface is based on a draft for
|
||||
* messages from PHP FIG. Individual implementing libraries will have their
|
||||
* own reference to interfaces. For example, see Guzzle.
|
||||
*
|
||||
* @throws \OpenStack\Transport\ForbiddenException
|
||||
* @throws \OpenStack\Transport\UnauthorizedException
|
||||
* @throws \OpenStack\Transport\FileNotFoundException
|
||||
* @throws \OpenStack\Transport\MethodNotAllowedException
|
||||
* @throws \OpenStack\Transport\ConflictException
|
||||
* @throws \OpenStack\Transport\LengthRequiredException
|
||||
* @throws \OpenStack\Transport\UnprocessableEntityException
|
||||
* @throws \OpenStack\Transport\ServerException
|
||||
* @throws \OpenStack\Exception
|
||||
*/
|
||||
public function doRequest($uri, $method = 'GET', array $headers = [], $body = '');
|
||||
|
||||
/**
|
||||
* Perform a request.
|
||||
*
|
||||
* Invoking this method causes a single request to be relayed over the
|
||||
* transporter. The transporter MUST be capable of handling multiple
|
||||
* invocations of a doRequest() call.
|
||||
*
|
||||
* @param string $uri The target URI.
|
||||
* @param string $method The method to be sent.
|
||||
* @param array $headers An array of name/value header pairs.
|
||||
* @param string $body The string containing the request body.
|
||||
*
|
||||
* @return \OpenStack\Transport\ResponseInterface The response. The response
|
||||
* is implicit rather than explicit. The interface is based on a draft for
|
||||
* messages from PHP FIG. Individual implementing libraries will have their
|
||||
* own reference to interfaces. For example, see Guzzle.
|
||||
*
|
||||
* @throws \OpenStack\Transport\ForbiddenException
|
||||
* @throws \OpenStack\Transport\UnauthorizedException
|
||||
* @throws \OpenStack\Transport\FileNotFoundException
|
||||
* @throws \OpenStack\Transport\MethodNotAllowedException
|
||||
* @throws \OpenStack\Transport\ConflictException
|
||||
* @throws \OpenStack\Transport\LengthRequiredException
|
||||
* @throws \OpenStack\Transport\UnprocessableEntityException
|
||||
* @throws \OpenStack\Transport\ServerException
|
||||
* @throws \OpenStack\Exception
|
||||
*/
|
||||
public function doRequest($uri, $method = 'GET', array $headers = [], $body = '');
|
||||
|
||||
|
||||
/**
|
||||
* Perform a request, but use a resource to read the body.
|
||||
*
|
||||
* This is a special version of the doRequest() function.
|
||||
* It handles a very spefic case where...
|
||||
*
|
||||
* - The HTTP verb requires a body (viz. PUT, POST)
|
||||
* - The body is in a resource, not a string
|
||||
*
|
||||
* Examples of appropriate cases for this variant:
|
||||
*
|
||||
* - Uploading large files.
|
||||
* - Streaming data out of a stream and into an HTTP request.
|
||||
* - Minimizing memory usage ($content strings are big).
|
||||
*
|
||||
* Note that all parameters are required.
|
||||
*
|
||||
* @param string $uri The target URI.
|
||||
* @param string $method The method to be sent.
|
||||
* @param array $headers An array of name/value header pairs.
|
||||
* @param mixed $resource The string with a file path or a stream URL; or a
|
||||
* file object resource. If it is a string, then it will be opened with the
|
||||
* default context. So if you need a special context, you should open the
|
||||
* file elsewhere and pass the resource in here.
|
||||
*
|
||||
* @return \OpenStack\Transport\ResponseInterface The response. The response
|
||||
* is implicit rather than explicit. The interface is based on a draft for
|
||||
* messages from PHP FIG. Individual implementing libraries will have their
|
||||
* own reference to interfaces. For example, see Guzzle.
|
||||
*
|
||||
* @throws \OpenStack\Transport\ForbiddenException
|
||||
* @throws \OpenStack\Transport\UnauthorizedException
|
||||
* @throws \OpenStack\Transport\FileNotFoundException
|
||||
* @throws \OpenStack\Transport\MethodNotAllowedException
|
||||
* @throws \OpenStack\Transport\ConflictException
|
||||
* @throws \OpenStack\Transport\LengthRequiredException
|
||||
* @throws \OpenStack\Transport\UnprocessableEntityException
|
||||
* @throws \OpenStack\Transport\ServerException
|
||||
* @throws \OpenStack\Exception
|
||||
*/
|
||||
public function doRequestWithResource($uri, $method, array $headers = [], $resource);
|
||||
/**
|
||||
* Perform a request, but use a resource to read the body.
|
||||
*
|
||||
* This is a special version of the doRequest() function.
|
||||
* It handles a very spefic case where...
|
||||
*
|
||||
* - The HTTP verb requires a body (viz. PUT, POST)
|
||||
* - The body is in a resource, not a string
|
||||
*
|
||||
* Examples of appropriate cases for this variant:
|
||||
*
|
||||
* - Uploading large files.
|
||||
* - Streaming data out of a stream and into an HTTP request.
|
||||
* - Minimizing memory usage ($content strings are big).
|
||||
*
|
||||
* Note that all parameters are required.
|
||||
*
|
||||
* @param string $uri The target URI.
|
||||
* @param string $method The method to be sent.
|
||||
* @param array $headers An array of name/value header pairs.
|
||||
* @param mixed $resource The string with a file path or a stream URL; or a
|
||||
* file object resource. If it is a string, then it will be opened with the
|
||||
* default context. So if you need a special context, you should open the
|
||||
* file elsewhere and pass the resource in here.
|
||||
*
|
||||
* @return \OpenStack\Transport\ResponseInterface The response. The response
|
||||
* is implicit rather than explicit. The interface is based on a draft for
|
||||
* messages from PHP FIG. Individual implementing libraries will have their
|
||||
* own reference to interfaces. For example, see Guzzle.
|
||||
*
|
||||
* @throws \OpenStack\Transport\ForbiddenException
|
||||
* @throws \OpenStack\Transport\UnauthorizedException
|
||||
* @throws \OpenStack\Transport\FileNotFoundException
|
||||
* @throws \OpenStack\Transport\MethodNotAllowedException
|
||||
* @throws \OpenStack\Transport\ConflictException
|
||||
* @throws \OpenStack\Transport\LengthRequiredException
|
||||
* @throws \OpenStack\Transport\UnprocessableEntityException
|
||||
* @throws \OpenStack\Transport\ServerException
|
||||
* @throws \OpenStack\Exception
|
||||
*/
|
||||
public function doRequestWithResource($uri, $method, array $headers = [], $resource);
|
||||
}
|
||||
|
@ -2,17 +2,17 @@
|
||||
/* ============================================================================
|
||||
(c) Copyright 2012-2014 Hewlett-Packard Development Company, L.P.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
============================================================================ */
|
||||
|
||||
namespace OpenStack\Transport;
|
||||
|
@ -2,17 +2,17 @@
|
||||
/* ============================================================================
|
||||
(c) Copyright 2012-2014 Hewlett-Packard Development Company, L.P.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
============================================================================ */
|
||||
|
||||
namespace OpenStack\Transport;
|
||||
|
@ -2,17 +2,17 @@
|
||||
/* ============================================================================
|
||||
(c) Copyright 2012-2014 Hewlett-Packard Development Company, L.P.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
============================================================================ */
|
||||
/**
|
||||
* @file
|
||||
|
@ -2,17 +2,17 @@
|
||||
/* ============================================================================
|
||||
(c) Copyright 2014 Hewlett-Packard Development Company, L.P.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
============================================================================ */
|
||||
/**
|
||||
* This file contains the interface for transporter clients.
|
||||
@ -20,203 +20,208 @@
|
||||
|
||||
namespace OpenStack\Transport;
|
||||
|
||||
class GuzzleClient implements ClientInterface, \Serializable {
|
||||
class GuzzleClient implements ClientInterface, \Serializable
|
||||
{
|
||||
const HTTP_USER_AGENT_SUFFIX = ' Guzzle/4.0';
|
||||
|
||||
const HTTP_USER_AGENT_SUFFIX = ' Guzzle/4.0';
|
||||
/**
|
||||
* The Guzzle client used for the implementation.
|
||||
*/
|
||||
protected $client;
|
||||
|
||||
/**
|
||||
* The Guzzle client used for the implementation.
|
||||
*/
|
||||
protected $client;
|
||||
protected $options;
|
||||
|
||||
protected $options;
|
||||
/**
|
||||
* Setup for the HTTP Client.
|
||||
*
|
||||
* @param array $options Options for the HTTP Client including:
|
||||
* - headers (array) A key/value mapping of default headers for each request.
|
||||
* - proxy (string) A proxy specified as a URI.
|
||||
* - debug (bool) True if debug output should be displayed.
|
||||
* - timeout (int) The timeout, in seconds, a request should wait before
|
||||
* timing out.
|
||||
* - ssl_verify (bool|string) True, the default, verifies the SSL certificate,
|
||||
* FALSE disables verification, and a string is the path to a CA to verify
|
||||
* against.
|
||||
* - client (mixed) A guzzle client object to use instead of the default.
|
||||
* This can be either a string to the class or an existing object. If an
|
||||
* existing object is passed in the other options will be ignored.
|
||||
*/
|
||||
public function __construct(array $options = [])
|
||||
{
|
||||
$this->options = $options;
|
||||
|
||||
/**
|
||||
* Setup for the HTTP Client.
|
||||
*
|
||||
* @param array $options Options for the HTTP Client including:
|
||||
* - headers (array) A key/value mapping of default headers for each request.
|
||||
* - proxy (string) A proxy specified as a URI.
|
||||
* - debug (bool) True if debug output should be displayed.
|
||||
* - timeout (int) The timeout, in seconds, a request should wait before
|
||||
* timing out.
|
||||
* - ssl_verify (bool|string) True, the default, verifies the SSL certificate,
|
||||
* FALSE disables verification, and a string is the path to a CA to verify
|
||||
* against.
|
||||
* - client (mixed) A guzzle client object to use instead of the default.
|
||||
* This can be either a string to the class or an existing object. If an
|
||||
* existing object is passed in the other options will be ignored.
|
||||
*/
|
||||
public function __construct(array $options = []) {
|
||||
$this->options = $options;
|
||||
|
||||
$this->client = $this->setup($options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup is a protected method to setup the client.
|
||||
*
|
||||
* The functionality would typically be in the constructor. It was broken out
|
||||
* to be used by the constructor and serialization process.
|
||||
*
|
||||
* @param array $options The options as passed to the constructor.
|
||||
* @return mixed The Guzzle based client.
|
||||
*/
|
||||
protected function setup(array $options = []) {
|
||||
// If no client has been passed in we create one. This is the default case.
|
||||
if (!isset($options['client']) || is_string($options['client'])) {
|
||||
$defaultOptions = ['defaults' => []];
|
||||
if (isset($options['headers'])) {
|
||||
$defaultOptions['defaults']['headers'] = $options['headers'];
|
||||
}
|
||||
if (isset($options['proxy'])) {
|
||||
$defaultOptions['defaults']['proxy'] = $options['proxy'];
|
||||
}
|
||||
if (isset($options['debug'])) {
|
||||
$defaultOptions['defaults']['debug'] = $options['debug'];
|
||||
}
|
||||
if (isset($options['ssl'])) {
|
||||
$defaultOptions['defaults']['verify'] = $options['ssl_verify'];
|
||||
}
|
||||
if (isset($options['timeout'])) {
|
||||
$defaultOptions['defaults']['timeout'] = $options['timeout'];
|
||||
}
|
||||
|
||||
// Add a user agent if not already specificed.
|
||||
if (!isset($defaultOptions['defaults']['headers']['User-Agent'])) {
|
||||
$defaultOptions['defaults']['headers']['User-Agent'] = self::HTTP_USER_AGENT . self::HTTP_USER_AGENT_SUFFIX;
|
||||
}
|
||||
|
||||
$clientClass = '\GuzzleHttp\Client';
|
||||
if (isset($options['client']) && is_string($options['client'])) {
|
||||
$clientClass = $options['client'];
|
||||
}
|
||||
|
||||
$options['client'] = new $clientClass($defaultOptions);
|
||||
$this->client = $this->setup($options);
|
||||
}
|
||||
|
||||
return $options['client'];
|
||||
}
|
||||
/**
|
||||
* Setup is a protected method to setup the client.
|
||||
*
|
||||
* The functionality would typically be in the constructor. It was broken out
|
||||
* to be used by the constructor and serialization process.
|
||||
*
|
||||
* @param array $options The options as passed to the constructor.
|
||||
* @return mixed The Guzzle based client.
|
||||
*/
|
||||
protected function setup(array $options = [])
|
||||
{
|
||||
// If no client has been passed in we create one. This is the default case.
|
||||
if (!isset($options['client']) || is_string($options['client'])) {
|
||||
$defaultOptions = ['defaults' => []];
|
||||
if (isset($options['headers'])) {
|
||||
$defaultOptions['defaults']['headers'] = $options['headers'];
|
||||
}
|
||||
if (isset($options['proxy'])) {
|
||||
$defaultOptions['defaults']['proxy'] = $options['proxy'];
|
||||
}
|
||||
if (isset($options['debug'])) {
|
||||
$defaultOptions['defaults']['debug'] = $options['debug'];
|
||||
}
|
||||
if (isset($options['ssl'])) {
|
||||
$defaultOptions['defaults']['verify'] = $options['ssl_verify'];
|
||||
}
|
||||
if (isset($options['timeout'])) {
|
||||
$defaultOptions['defaults']['timeout'] = $options['timeout'];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function doRequest($uri, $method = 'GET', array $headers = [], $body = '') {
|
||||
// Add a user agent if not already specificed.
|
||||
if (!isset($defaultOptions['defaults']['headers']['User-Agent'])) {
|
||||
$defaultOptions['defaults']['headers']['User-Agent'] = self::HTTP_USER_AGENT . self::HTTP_USER_AGENT_SUFFIX;
|
||||
}
|
||||
|
||||
$options = [
|
||||
'headers' => $headers,
|
||||
'body' => $body,
|
||||
];
|
||||
$clientClass = '\GuzzleHttp\Client';
|
||||
if (isset($options['client']) && is_string($options['client'])) {
|
||||
$clientClass = $options['client'];
|
||||
}
|
||||
|
||||
// We use our own exceptions for errors to provide a common exception
|
||||
// interface to applications implementing the SDK.
|
||||
try {
|
||||
$response = $this->client->send($this->client->createRequest($method, $uri, $options));
|
||||
} catch(\GuzzleHttp\Exception\ClientException $e) {
|
||||
$this->handleException($e);
|
||||
} catch(\GuzzleHttp\Exception\ServerException $e) {
|
||||
$this->handleException($e);
|
||||
} catch(\GuzzleHttp\Exception\RequestException $e) {
|
||||
$this->handleException($e);
|
||||
$options['client'] = new $clientClass($defaultOptions);
|
||||
}
|
||||
|
||||
return $options['client'];
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function doRequest($uri, $method = 'GET', array $headers = [], $body = '')
|
||||
{
|
||||
$options = [
|
||||
'headers' => $headers,
|
||||
'body' => $body,
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function doRequestWithResource($uri, $method, array $headers = [], $resource) {
|
||||
// We use our own exceptions for errors to provide a common exception
|
||||
// interface to applications implementing the SDK.
|
||||
try {
|
||||
$response = $this->client->send($this->client->createRequest($method, $uri, $options));
|
||||
} catch (\GuzzleHttp\Exception\ClientException $e) {
|
||||
$this->handleException($e);
|
||||
} catch (\GuzzleHttp\Exception\ServerException $e) {
|
||||
$this->handleException($e);
|
||||
} catch (\GuzzleHttp\Exception\RequestException $e) {
|
||||
$this->handleException($e);
|
||||
}
|
||||
|
||||
// Guzzle messes with the resource in such a manner that it can no longer be
|
||||
// used by something else after the fact. So, we clone the content into
|
||||
// temporary stream.
|
||||
$tmp = $out = fopen('php://temp', 'wb+');
|
||||
stream_copy_to_stream($resource, $tmp);
|
||||
|
||||
$options = [
|
||||
'headers' => $headers,
|
||||
'body' => $tmp,
|
||||
];
|
||||
|
||||
// We use our own exceptions for errors to provide a common exception
|
||||
// interface to applications implementing the SDK.
|
||||
try {
|
||||
$response = $this->client->send($this->client->createRequest($method, $uri, $options));
|
||||
} catch(\GuzzleHttp\Exception\ClientException $e) {
|
||||
$this->handleException($e);
|
||||
} catch(\GuzzleHttp\Exception\ServerException $e) {
|
||||
$this->handleException($e);
|
||||
} catch(\GuzzleHttp\Exception\RequestException $e) {
|
||||
$this->handleException($e);
|
||||
return $response;
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function doRequestWithResource($uri, $method, array $headers = [], $resource)
|
||||
{
|
||||
// Guzzle messes with the resource in such a manner that it can no longer be
|
||||
// used by something else after the fact. So, we clone the content into
|
||||
// temporary stream.
|
||||
$tmp = $out = fopen('php://temp', 'wb+');
|
||||
stream_copy_to_stream($resource, $tmp);
|
||||
|
||||
/**
|
||||
* Handle errors on a response.
|
||||
*
|
||||
* @param mixed The Guzzle exception.
|
||||
*
|
||||
* @return \OpenStack\Transport\ResponseInterface The response.
|
||||
*
|
||||
* @throws \OpenStack\Transport\ForbiddenException
|
||||
* @throws \OpenStack\Transport\UnauthorizedException
|
||||
* @throws \OpenStack\Transport\FileNotFoundException
|
||||
* @throws \OpenStack\Transport\MethodNotAllowedException
|
||||
* @throws \OpenStack\Transport\ConflictException
|
||||
* @throws \OpenStack\Transport\LengthRequiredException
|
||||
* @throws \OpenStack\Transport\UnprocessableEntityException
|
||||
* @throws \OpenStack\Transport\ServerException
|
||||
* @throws \OpenStack\Exception
|
||||
*/
|
||||
protected function handleException($exception) {
|
||||
$options = [
|
||||
'headers' => $headers,
|
||||
'body' => $tmp,
|
||||
];
|
||||
|
||||
$response = $exception->getResponse();
|
||||
$request = $exception->getRequest();
|
||||
// We use our own exceptions for errors to provide a common exception
|
||||
// interface to applications implementing the SDK.
|
||||
try {
|
||||
$response = $this->client->send($this->client->createRequest($method, $uri, $options));
|
||||
} catch (\GuzzleHttp\Exception\ClientException $e) {
|
||||
$this->handleException($e);
|
||||
} catch (\GuzzleHttp\Exception\ServerException $e) {
|
||||
$this->handleException($e);
|
||||
} catch (\GuzzleHttp\Exception\RequestException $e) {
|
||||
$this->handleException($e);
|
||||
}
|
||||
|
||||
if (!is_null($response)) {
|
||||
$code = $response->getStatusCode();
|
||||
|
||||
switch ($code) {
|
||||
case '403':
|
||||
throw new \OpenStack\Transport\ForbiddenException($response->getReasonPhrase());
|
||||
case '401':
|
||||
throw new \OpenStack\Transport\UnauthorizedException($response->getReasonPhrase());
|
||||
case '404':
|
||||
throw new \OpenStack\Transport\FileNotFoundException($response->getReasonPhrase() . " ({$response->getEffectiveUrl()})");
|
||||
case '405':
|
||||
throw new \OpenStack\Transport\MethodNotAllowedException($response->getReasonPhrase() . " ({$request->getMethod()} {$response->getEffectiveUrl()})");
|
||||
case '409':
|
||||
throw new \OpenStack\Transport\ConflictException($response->getReasonPhrase());
|
||||
case '412':
|
||||
throw new \OpenStack\Transport\LengthRequiredException($response->getReasonPhrase());
|
||||
case '422':
|
||||
throw new \OpenStack\Transport\UnprocessableEntityException($response->getReasonPhrase());
|
||||
case '500':
|
||||
throw new \OpenStack\Transport\ServerException($response->getReasonPhrase());
|
||||
default:
|
||||
throw new \OpenStack\Exception($response->getReasonPhrase());
|
||||
}
|
||||
}
|
||||
// The exception was one other than a HTTP error. For example, a HTTP layer
|
||||
// timeout occurred.
|
||||
else {
|
||||
throw new \OpenStack\Exception($exception->getMessage());
|
||||
return $response;
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
/**
|
||||
* Handle errors on a response.
|
||||
*
|
||||
* @param mixed The Guzzle exception.
|
||||
*
|
||||
* @return \OpenStack\Transport\ResponseInterface The response.
|
||||
*
|
||||
* @throws \OpenStack\Transport\ForbiddenException
|
||||
* @throws \OpenStack\Transport\UnauthorizedException
|
||||
* @throws \OpenStack\Transport\FileNotFoundException
|
||||
* @throws \OpenStack\Transport\MethodNotAllowedException
|
||||
* @throws \OpenStack\Transport\ConflictException
|
||||
* @throws \OpenStack\Transport\LengthRequiredException
|
||||
* @throws \OpenStack\Transport\UnprocessableEntityException
|
||||
* @throws \OpenStack\Transport\ServerException
|
||||
* @throws \OpenStack\Exception
|
||||
*/
|
||||
protected function handleException($exception)
|
||||
{
|
||||
$response = $exception->getResponse();
|
||||
$request = $exception->getRequest();
|
||||
|
||||
public function serialize() {
|
||||
$data = ['options' => $this->options];
|
||||
return serialize($data);
|
||||
}
|
||||
if (!is_null($response)) {
|
||||
$code = $response->getStatusCode();
|
||||
|
||||
public function unserialize($data) {
|
||||
$vals = unserialize($data);
|
||||
$this->options = $vals['options'];
|
||||
$this->client = $this->setup($vals['options']);
|
||||
}
|
||||
switch ($code) {
|
||||
case '403':
|
||||
throw new \OpenStack\Transport\ForbiddenException($response->getReasonPhrase());
|
||||
case '401':
|
||||
throw new \OpenStack\Transport\UnauthorizedException($response->getReasonPhrase());
|
||||
case '404':
|
||||
throw new \OpenStack\Transport\FileNotFoundException($response->getReasonPhrase() . " ({$response->getEffectiveUrl()})");
|
||||
case '405':
|
||||
throw new \OpenStack\Transport\MethodNotAllowedException($response->getReasonPhrase() . " ({$request->getMethod()} {$response->getEffectiveUrl()})");
|
||||
case '409':
|
||||
throw new \OpenStack\Transport\ConflictException($response->getReasonPhrase());
|
||||
case '412':
|
||||
throw new \OpenStack\Transport\LengthRequiredException($response->getReasonPhrase());
|
||||
case '422':
|
||||
throw new \OpenStack\Transport\UnprocessableEntityException($response->getReasonPhrase());
|
||||
case '500':
|
||||
throw new \OpenStack\Transport\ServerException($response->getReasonPhrase());
|
||||
default:
|
||||
throw new \OpenStack\Exception($response->getReasonPhrase());
|
||||
}
|
||||
}
|
||||
// The exception was one other than a HTTP error. For example, a HTTP layer
|
||||
// timeout occurred.
|
||||
else {
|
||||
throw new \OpenStack\Exception($exception->getMessage());
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
public function serialize()
|
||||
{
|
||||
$data = ['options' => $this->options];
|
||||
|
||||
return serialize($data);
|
||||
}
|
||||
|
||||
public function unserialize($data)
|
||||
{
|
||||
$vals = unserialize($data);
|
||||
$this->options = $vals['options'];
|
||||
$this->client = $this->setup($vals['options']);
|
||||
}
|
||||
}
|
||||
|
@ -2,17 +2,17 @@
|
||||
/* ============================================================================
|
||||
(c) Copyright 2012-2014 Hewlett-Packard Development Company, L.P.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
============================================================================ */
|
||||
|
||||
namespace OpenStack\Transport;
|
||||
|
@ -2,17 +2,17 @@
|
||||
/* ============================================================================
|
||||
(c) Copyright 2012-2014 Hewlett-Packard Development Company, L.P.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
============================================================================ */
|
||||
|
||||
namespace OpenStack\Transport;
|
||||
|
@ -2,17 +2,17 @@
|
||||
/* ============================================================================
|
||||
(c) Copyright 2014 Hewlett-Packard Development Company, L.P.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
============================================================================ */
|
||||
/**
|
||||
* This file contains the response interface for a HTTP request.
|
||||
@ -26,157 +26,158 @@ namespace OpenStack\Transport;
|
||||
* This interface is equivalent to the proposed PHP FIG http message interface
|
||||
* for a response that can be found at https://github.com/php-fig/fig-standards/blob/master/proposed/http-message.md#33-psrhttpresponseinterface
|
||||
*/
|
||||
interface ResponseInterface {
|
||||
/**
|
||||
* Gets the response Status-Code, a 3-digit integer result code of the
|
||||
* server's attempt to understand and satisfy the request.
|
||||
*
|
||||
* @return integer Status code.
|
||||
*/
|
||||
public function getStatusCode();
|
||||
interface ResponseInterface
|
||||
{
|
||||
/**
|
||||
* Gets the response Status-Code, a 3-digit integer result code of the
|
||||
* server's attempt to understand and satisfy the request.
|
||||
*
|
||||
* @return integer Status code.
|
||||
*/
|
||||
public function getStatusCode();
|
||||
|
||||
/**
|
||||
* Gets the response Reason-Phrase, a short textual description of the
|
||||
* Status-Code.
|
||||
*
|
||||
* Because a Reason-Phrase is not a required element in response
|
||||
* Status-Line, the Reason-Phrase value MAY be null. Implementations MAY
|
||||
* choose to return the default RFC 2616 recommended reason phrase for the
|
||||
* response's Status-Code.
|
||||
*
|
||||
* @return string|null Reason phrase, or null if unknown.
|
||||
*/
|
||||
public function getReasonPhrase();
|
||||
|
||||
/**
|
||||
* Gets the HTTP protocol version.
|
||||
*
|
||||
* @return string HTTP protocol version.
|
||||
*/
|
||||
public function getProtocolVersion();
|
||||
/**
|
||||
* Gets the response Reason-Phrase, a short textual description of the
|
||||
* Status-Code.
|
||||
*
|
||||
* Because a Reason-Phrase is not a required element in response
|
||||
* Status-Line, the Reason-Phrase value MAY be null. Implementations MAY
|
||||
* choose to return the default RFC 2616 recommended reason phrase for the
|
||||
* response's Status-Code.
|
||||
*
|
||||
* @return string|null Reason phrase, or null if unknown.
|
||||
*/
|
||||
public function getReasonPhrase();
|
||||
|
||||
/**
|
||||
* Gets the body of the message.
|
||||
*
|
||||
* @return StreamInterface|null Returns the body, or null if not set.
|
||||
*/
|
||||
public function getBody();
|
||||
/**
|
||||
* Gets the HTTP protocol version.
|
||||
*
|
||||
* @return string HTTP protocol version.
|
||||
*/
|
||||
public function getProtocolVersion();
|
||||
|
||||
/**
|
||||
* Sets the body of the message.
|
||||
*
|
||||
* The body MUST be a StreamInterface object. Setting the body to null MUST
|
||||
* remove the existing body.
|
||||
*
|
||||
* @param StreamInterface|null $body Body.
|
||||
*
|
||||
* @return self Returns the message.
|
||||
*
|
||||
* @throws \InvalidArgumentException When the body is not valid.
|
||||
*/
|
||||
public function setBody(StreamInterface $body = null);
|
||||
/**
|
||||
* Gets the body of the message.
|
||||
*
|
||||
* @return StreamInterface|null Returns the body, or null if not set.
|
||||
*/
|
||||
public function getBody();
|
||||
|
||||
/**
|
||||
* Gets all message headers.
|
||||
*
|
||||
* The keys represent the header name as it will be sent over the wire, and
|
||||
* each value is an array of strings associated with the header.
|
||||
*
|
||||
* // Represent the headers as a string
|
||||
* foreach ($message->getHeaders() as $name => $values) {
|
||||
* echo $name . ": " . implode(", ", $values);
|
||||
* }
|
||||
*
|
||||
* @return array Returns an associative array of the message's headers.
|
||||
*/
|
||||
public function getHeaders();
|
||||
/**
|
||||
* Sets the body of the message.
|
||||
*
|
||||
* The body MUST be a StreamInterface object. Setting the body to null MUST
|
||||
* remove the existing body.
|
||||
*
|
||||
* @param StreamInterface|null $body Body.
|
||||
*
|
||||
* @return self Returns the message.
|
||||
*
|
||||
* @throws \InvalidArgumentException When the body is not valid.
|
||||
*/
|
||||
public function setBody(StreamInterface $body = null);
|
||||
|
||||
/**
|
||||
* Checks if a header exists by the given case-insensitive name.
|
||||
*
|
||||
* @param string $header Case-insensitive header name.
|
||||
*
|
||||
* @return bool Returns true if any header names match the given header
|
||||
* name using a case-insensitive string comparison. Returns false if
|
||||
* no matching header name is found in the message.
|
||||
*/
|
||||
public function hasHeader($header);
|
||||
/**
|
||||
* Gets all message headers.
|
||||
*
|
||||
* The keys represent the header name as it will be sent over the wire, and
|
||||
* each value is an array of strings associated with the header.
|
||||
*
|
||||
* // Represent the headers as a string
|
||||
* foreach ($message->getHeaders() as $name => $values) {
|
||||
* echo $name . ": " . implode(", ", $values);
|
||||
* }
|
||||
*
|
||||
* @return array Returns an associative array of the message's headers.
|
||||
*/
|
||||
public function getHeaders();
|
||||
|
||||
/**
|
||||
* Retrieve a header by the given case-insensitive name.
|
||||
*
|
||||
* By default, this method returns all of the header values of the given
|
||||
* case-insensitive header name as a string concatenated together using
|
||||
* a comma. Because some header should not be concatenated together using a
|
||||
* comma, this method provides a Boolean argument that can be used to
|
||||
* retrieve the associated header values as an array of strings.
|
||||
*
|
||||
* @param string $header Case-insensitive header name.
|
||||
* @param bool $asArray Set to true to retrieve the header value as an
|
||||
* array of strings.
|
||||
*
|
||||
* @return array|string
|
||||
*/
|
||||
public function getHeader($header, $asArray = false);
|
||||
/**
|
||||
* Checks if a header exists by the given case-insensitive name.
|
||||
*
|
||||
* @param string $header Case-insensitive header name.
|
||||
*
|
||||
* @return bool Returns true if any header names match the given header
|
||||
* name using a case-insensitive string comparison. Returns false if
|
||||
* no matching header name is found in the message.
|
||||
*/
|
||||
public function hasHeader($header);
|
||||
|
||||
/**
|
||||
* Sets a header, replacing any existing values of any headers with the
|
||||
* same case-insensitive name.
|
||||
*
|
||||
* The header values MUST be a string or an array of strings.
|
||||
*
|
||||
* @param string $header Header name
|
||||
* @param string|array $value Header value(s)
|
||||
*
|
||||
* @return self Returns the message.
|
||||
*/
|
||||
public function setHeader($header, $value);
|
||||
/**
|
||||
* Retrieve a header by the given case-insensitive name.
|
||||
*
|
||||
* By default, this method returns all of the header values of the given
|
||||
* case-insensitive header name as a string concatenated together using
|
||||
* a comma. Because some header should not be concatenated together using a
|
||||
* comma, this method provides a Boolean argument that can be used to
|
||||
* retrieve the associated header values as an array of strings.
|
||||
*
|
||||
* @param string $header Case-insensitive header name.
|
||||
* @param bool $asArray Set to true to retrieve the header value as an
|
||||
* array of strings.
|
||||
*
|
||||
* @return array|string
|
||||
*/
|
||||
public function getHeader($header, $asArray = false);
|
||||
|
||||
/**
|
||||
* Sets headers, replacing any headers that have already been set on the
|
||||
* message.
|
||||
*
|
||||
* The array keys MUST be a string. The array values must be either a
|
||||
* string or an array of strings.
|
||||
*
|
||||
* @param array $headers Headers to set.
|
||||
*
|
||||
* @return self Returns the message.
|
||||
*/
|
||||
public function setHeaders(array $headers);
|
||||
/**
|
||||
* Sets a header, replacing any existing values of any headers with the
|
||||
* same case-insensitive name.
|
||||
*
|
||||
* The header values MUST be a string or an array of strings.
|
||||
*
|
||||
* @param string $header Header name
|
||||
* @param string|array $value Header value(s)
|
||||
*
|
||||
* @return self Returns the message.
|
||||
*/
|
||||
public function setHeader($header, $value);
|
||||
|
||||
/**
|
||||
* Appends a header value to any existing values associated with the
|
||||
* given header name.
|
||||
*
|
||||
* @param string $header Header name to add
|
||||
* @param string $value Value of the header
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function addHeader($header, $value);
|
||||
/**
|
||||
* Sets headers, replacing any headers that have already been set on the
|
||||
* message.
|
||||
*
|
||||
* The array keys MUST be a string. The array values must be either a
|
||||
* string or an array of strings.
|
||||
*
|
||||
* @param array $headers Headers to set.
|
||||
*
|
||||
* @return self Returns the message.
|
||||
*/
|
||||
public function setHeaders(array $headers);
|
||||
|
||||
/**
|
||||
* Merges in an associative array of headers.
|
||||
*
|
||||
* Each array key MUST be a string representing the case-insensitive name
|
||||
* of a header. Each value MUST be either a string or an array of strings.
|
||||
* For each value, the value is appended to any existing header of the same
|
||||
* name, or, if a header does not already exist by the given name, then the
|
||||
* header is added.
|
||||
*
|
||||
* @param array $headers Associative array of headers to add to the message
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function addHeaders(array $headers);
|
||||
/**
|
||||
* Appends a header value to any existing values associated with the
|
||||
* given header name.
|
||||
*
|
||||
* @param string $header Header name to add
|
||||
* @param string $value Value of the header
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function addHeader($header, $value);
|
||||
|
||||
/**
|
||||
* Remove a specific header by case-insensitive name.
|
||||
*
|
||||
* @param string $header HTTP header to remove
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function removeHeader($header);
|
||||
}
|
||||
/**
|
||||
* Merges in an associative array of headers.
|
||||
*
|
||||
* Each array key MUST be a string representing the case-insensitive name
|
||||
* of a header. Each value MUST be either a string or an array of strings.
|
||||
* For each value, the value is appended to any existing header of the same
|
||||
* name, or, if a header does not already exist by the given name, then the
|
||||
* header is added.
|
||||
*
|
||||
* @param array $headers Associative array of headers to add to the message
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function addHeaders(array $headers);
|
||||
|
||||
/**
|
||||
* Remove a specific header by case-insensitive name.
|
||||
*
|
||||
* @param string $header HTTP header to remove
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function removeHeader($header);
|
||||
}
|
||||
|
@ -2,17 +2,17 @@
|
||||
/* ============================================================================
|
||||
(c) Copyright 2012-2014 Hewlett-Packard Development Company, L.P.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
============================================================================ */
|
||||
|
||||
namespace OpenStack\Transport;
|
||||
|
@ -2,17 +2,17 @@
|
||||
/* ============================================================================
|
||||
(c) Copyright 2012-2014 Hewlett-Packard Development Company, L.P.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
============================================================================ */
|
||||
/**
|
||||
* The authorization exception.
|
||||
|
@ -2,17 +2,17 @@
|
||||
/* ============================================================================
|
||||
(c) Copyright 2012-2014 Hewlett-Packard Development Company, L.P.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
============================================================================ */
|
||||
|
||||
namespace OpenStack\Transport;
|
||||
|
@ -2,17 +2,17 @@
|
||||
/* ============================================================================
|
||||
(c) Copyright 2012-2014 Hewlett-Packard Development Company, L.P.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
============================================================================ */
|
||||
/**
|
||||
* This is a simple command-line test for authentication.
|
||||
@ -27,10 +27,10 @@ use \OpenStack\Storage\ObjectStorage;
|
||||
use \OpenStack\Services\IdentityService;
|
||||
|
||||
$config = array(
|
||||
'transport' => '\OpenStack\Transport\PHPStreamTransport',
|
||||
'transport.timeout' => 240,
|
||||
//'transport.debug' => 1,
|
||||
'transport.ssl.verify' => 0,
|
||||
'transport' => '\OpenStack\Transport\PHPStreamTransport',
|
||||
'transport.timeout' => 240,
|
||||
//'transport.debug' => 1,
|
||||
'transport.ssl.verify' => 0,
|
||||
);
|
||||
|
||||
\OpenStack\Autoloader::useAutoloader();
|
||||
@ -48,14 +48,13 @@ In both cases, you must supply a URL to the Identity Services endpoint.
|
||||
$usage = "php {$argv[0]} USERNAME PASSWORD URL [TENANT_ID]";
|
||||
|
||||
if ($argc > 1 && $argv[1] == '--help') {
|
||||
print PHP_EOL . "\t" . $usage . PHP_EOL;
|
||||
print PHP_EOL . $help . PHP_EOL;
|
||||
exit(1);
|
||||
}
|
||||
elseif ($argc < 4) {
|
||||
print 'USERNAME, PASSWORD, and URL are all required.' . PHP_EOL;
|
||||
print $usage . PHP_EOL;
|
||||
exit(1);
|
||||
print PHP_EOL . "\t" . $usage . PHP_EOL;
|
||||
print PHP_EOL . $help . PHP_EOL;
|
||||
exit(1);
|
||||
} elseif ($argc < 4) {
|
||||
print 'USERNAME, PASSWORD, and URL are all required.' . PHP_EOL;
|
||||
print $usage . PHP_EOL;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$offset = 0;
|
||||
@ -66,7 +65,7 @@ $uri = $argv[3 + $offset];
|
||||
|
||||
$tenantId = NULL;
|
||||
if (!empty($argv[4 + $offset])) {
|
||||
$tenantId = $argv[4 + $offset];
|
||||
$tenantId = $argv[4 + $offset];
|
||||
}
|
||||
|
||||
/*
|
||||
@ -79,8 +78,8 @@ $cs = new IdentityService($uri);
|
||||
$token = $cs->authenticateAsUser($user, $password, $tenantId);
|
||||
|
||||
if (empty($token)) {
|
||||
print "Authentication seemed to succeed, but no token was returned." . PHP_EOL;
|
||||
exit(1);
|
||||
print "Authentication seemed to succeed, but no token was returned." . PHP_EOL;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$t = "You are logged in as %s with token %s (good until %s)." . PHP_EOL;
|
||||
@ -93,7 +92,7 @@ print "The following services are available on this user:" . PHP_EOL;
|
||||
|
||||
$services = $cs->serviceCatalog();
|
||||
foreach ($services as $service) {
|
||||
print "\t" . $service['name'] . PHP_EOL;
|
||||
print "\t" . $service['name'] . PHP_EOL;
|
||||
}
|
||||
|
||||
//print_r($services);
|
||||
|
@ -2,17 +2,17 @@
|
||||
/* ============================================================================
|
||||
(c) Copyright 2012-2014 Hewlett-Packard Development Company, L.P.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
============================================================================ */
|
||||
/**
|
||||
* Base test case.
|
||||
@ -25,233 +25,232 @@
|
||||
* This group contains all of the unit testing classes.
|
||||
*/
|
||||
|
||||
|
||||
namespace OpenStack\Tests;
|
||||
|
||||
/**
|
||||
* @ingroup Tests
|
||||
*/
|
||||
class TestCase extends \PHPUnit_Framework_TestCase {
|
||||
class TestCase extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public static $settings = array();
|
||||
|
||||
public static $settings = array();
|
||||
public static $ostore = NULL;
|
||||
|
||||
public static $ostore = NULL;
|
||||
/**
|
||||
* The IdentityService instance.
|
||||
*/
|
||||
public static $ident;
|
||||
|
||||
/**
|
||||
* The IdentityService instance.
|
||||
*/
|
||||
public static $ident;
|
||||
public static $httpClient = NULL;
|
||||
|
||||
public static $httpClient = NULL;
|
||||
//public function __construct(score $score = NULL, locale $locale = NULL, adapter $adapter = NULL) {
|
||||
public static function setUpBeforeClass()
|
||||
{
|
||||
global $bootstrap_settings;
|
||||
|
||||
//public function __construct(score $score = NULL, locale $locale = NULL, adapter $adapter = NULL) {
|
||||
public static function setUpBeforeClass() {
|
||||
global $bootstrap_settings;
|
||||
if (!isset($bootstrap_settings)) {
|
||||
$bootstrap_settings = array();
|
||||
}
|
||||
self::$settings = $bootstrap_settings;
|
||||
|
||||
if (!isset($bootstrap_settings)) {
|
||||
$bootstrap_settings = array();
|
||||
}
|
||||
self::$settings = $bootstrap_settings;
|
||||
//$this->setTestNamespace('Tests\Units');
|
||||
if (file_exists('test/settings.ini')) {
|
||||
self::$settings += parse_ini_file('test/settings.ini');
|
||||
} else {
|
||||
throw new \Exception('Could not access test/settings.ini');
|
||||
}
|
||||
|
||||
\OpenStack\Autoloader::useAutoloader();
|
||||
\OpenStack\Bootstrap::setConfiguration(self::$settings);
|
||||
|
||||
//$this->setTestNamespace('Tests\Units');
|
||||
if (file_exists('test/settings.ini')) {
|
||||
self::$settings += parse_ini_file('test/settings.ini');
|
||||
}
|
||||
else {
|
||||
throw new \Exception('Could not access test/settings.ini');
|
||||
//parent::__construct($score, $locale, $adapter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a configuration value.
|
||||
*
|
||||
* Optionally, specify a default value to be used
|
||||
* if none was found.
|
||||
*/
|
||||
public static function conf($name, $default = NULL)
|
||||
{
|
||||
if (isset(self::$settings[$name])) {
|
||||
return self::$settings[$name];
|
||||
}
|
||||
|
||||
\OpenStack\Autoloader::useAutoloader();
|
||||
\OpenStack\Bootstrap::setConfiguration(self::$settings);
|
||||
|
||||
//parent::__construct($score, $locale, $adapter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a configuration value.
|
||||
*
|
||||
* Optionally, specify a default value to be used
|
||||
* if none was found.
|
||||
*/
|
||||
public static function conf($name, $default = NULL) {
|
||||
if (isset(self::$settings[$name])) {
|
||||
return self::$settings[$name];
|
||||
return $default;
|
||||
}
|
||||
return $default;
|
||||
}
|
||||
|
||||
protected $containerFixture = NULL;
|
||||
protected $containerFixture = NULL;
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
protected function swiftAuth() {
|
||||
|
||||
$user = self::$settings['openstack.swift.account'];
|
||||
$key = self::$settings['openstack.swift.key'];
|
||||
$url = self::$settings['openstack.swift.url'];
|
||||
//$url = self::$settings['openstack.identity.url'];
|
||||
|
||||
return \OpenStack\Storage\ObjectStorage::newFromSwiftAuth($user, $key, $url, $this->getTransportClient());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a handle to an IdentityService object.
|
||||
*
|
||||
* Authentication is performed, and the returned
|
||||
* service has its tenant ID set already.
|
||||
*
|
||||
* <?php
|
||||
* // Get the current token.
|
||||
* $this->identity()->token();
|
||||
* ?>
|
||||
*/
|
||||
protected function identity($reset = FALSE) {
|
||||
|
||||
if ($reset || empty(self::$ident)) {
|
||||
$user = self::conf('openstack.identity.username');
|
||||
$pass = self::conf('openstack.identity.password');
|
||||
$tenantId = self::conf('openstack.identity.tenantId');
|
||||
$url = self::conf('openstack.identity.url');
|
||||
|
||||
$is = new \OpenStack\Services\IdentityService($url);
|
||||
|
||||
$token = $is->authenticateAsUser($user, $pass, $tenantId);
|
||||
|
||||
self::$ident = $is;
|
||||
|
||||
}
|
||||
return self::$ident;
|
||||
}
|
||||
|
||||
protected function objectStore($reset = FALSE) {
|
||||
|
||||
if ($reset || empty(self::$ostore)) {
|
||||
$ident = $this->identity($reset);
|
||||
|
||||
$objStore = \OpenStack\Storage\ObjectStorage::newFromIdentity($ident, self::$settings['openstack.swift.region'], $this->getTransportClient());
|
||||
|
||||
self::$ostore = $objStore;
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
protected function swiftAuth()
|
||||
{
|
||||
$user = self::$settings['openstack.swift.account'];
|
||||
$key = self::$settings['openstack.swift.key'];
|
||||
$url = self::$settings['openstack.swift.url'];
|
||||
//$url = self::$settings['openstack.identity.url'];
|
||||
return \OpenStack\Storage\ObjectStorage::newFromSwiftAuth($user, $key, $url, $this->getTransportClient());
|
||||
|
||||
}
|
||||
|
||||
return self::$ostore;
|
||||
}
|
||||
/**
|
||||
* Get a handle to an IdentityService object.
|
||||
*
|
||||
* Authentication is performed, and the returned
|
||||
* service has its tenant ID set already.
|
||||
*
|
||||
* <?php
|
||||
* // Get the current token.
|
||||
* $this->identity()->token();
|
||||
* ?>
|
||||
*/
|
||||
protected function identity($reset = FALSE)
|
||||
{
|
||||
if ($reset || empty(self::$ident)) {
|
||||
$user = self::conf('openstack.identity.username');
|
||||
$pass = self::conf('openstack.identity.password');
|
||||
$tenantId = self::conf('openstack.identity.tenantId');
|
||||
$url = self::conf('openstack.identity.url');
|
||||
|
||||
/**
|
||||
* Get a container from the server.
|
||||
*/
|
||||
protected function containerFixture() {
|
||||
$is = new \OpenStack\Services\IdentityService($url);
|
||||
|
||||
if (empty($this->containerFixture)) {
|
||||
$store = $this->objectStore();
|
||||
$cname = self::$settings['openstack.swift.container'];
|
||||
$token = $is->authenticateAsUser($user, $pass, $tenantId);
|
||||
|
||||
try {
|
||||
$store->createContainer($cname);
|
||||
$this->containerFixture = $store->container($cname);
|
||||
self::$ident = $is;
|
||||
|
||||
}
|
||||
|
||||
return self::$ident;
|
||||
}
|
||||
|
||||
protected function objectStore($reset = FALSE)
|
||||
{
|
||||
if ($reset || empty(self::$ostore)) {
|
||||
$ident = $this->identity($reset);
|
||||
|
||||
$objStore = \OpenStack\Storage\ObjectStorage::newFromIdentity($ident, self::$settings['openstack.swift.region'], $this->getTransportClient());
|
||||
|
||||
self::$ostore = $objStore;
|
||||
|
||||
}
|
||||
|
||||
return self::$ostore;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a container from the server.
|
||||
*/
|
||||
protected function containerFixture()
|
||||
{
|
||||
if (empty($this->containerFixture)) {
|
||||
$store = $this->objectStore();
|
||||
$cname = self::$settings['openstack.swift.container'];
|
||||
|
||||
try {
|
||||
$store->createContainer($cname);
|
||||
$this->containerFixture = $store->container($cname);
|
||||
|
||||
}
|
||||
// This is why PHP needs 'finally'.
|
||||
catch (\Exception $e) {
|
||||
// Delete the container.
|
||||
$store->deleteContainer($cname);
|
||||
throw $e;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $this->containerFixture;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear and destroy a container.
|
||||
*
|
||||
* Destroy all of the files in a container, then destroy the
|
||||
* container.
|
||||
*
|
||||
* If the container doesn't exist, this will silently return.
|
||||
*
|
||||
* @param string $cname The name of the container.
|
||||
*/
|
||||
protected function eradicateContainer($cname)
|
||||
{
|
||||
$store = $this->objectStore();
|
||||
try {
|
||||
$container = $store->container($cname);
|
||||
}
|
||||
// The container was never created.
|
||||
catch (\OpenStack\Transport\FileNotFoundException $e) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($container as $object) {
|
||||
try {
|
||||
$container->delete($object->name());
|
||||
} catch (\Exception $e) {}
|
||||
}
|
||||
|
||||
}
|
||||
// This is why PHP needs 'finally'.
|
||||
catch (\Exception $e) {
|
||||
// Delete the container.
|
||||
$store->deleteContainer($cname);
|
||||
throw $e;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $this->containerFixture;
|
||||
}
|
||||
/**
|
||||
* Retrieve the HTTP Transport Client
|
||||
*
|
||||
* @return \OpenStack\Transport\ClientInterface A transport client.
|
||||
*/
|
||||
public static function getTransportClient()
|
||||
{
|
||||
if (is_null(self::$httpClient)) {
|
||||
$options = [];
|
||||
if (isset(self::$settings['transport.proxy'])) {
|
||||
$options['proxy'] = self::$settings['transport.proxy'];
|
||||
}
|
||||
if (isset(self::$settings['transport.debug'])) {
|
||||
$options['debug'] = self::$settings['transport.debug'];
|
||||
}
|
||||
if (isset(self::$settings['transport.ssl.verify'])) {
|
||||
$options['ssl_verify'] = self::$settings['transport.ssl.verify'];
|
||||
}
|
||||
if (isset(self::$settings['transport.timeout'])) {
|
||||
$options['timeout'] = self::$settings['transport.timeout'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear and destroy a container.
|
||||
*
|
||||
* Destroy all of the files in a container, then destroy the
|
||||
* container.
|
||||
*
|
||||
* If the container doesn't exist, this will silently return.
|
||||
*
|
||||
* @param string $cname The name of the container.
|
||||
*/
|
||||
protected function eradicateContainer($cname) {
|
||||
$store = $this->objectStore();
|
||||
try {
|
||||
$container = $store->container($cname);
|
||||
}
|
||||
// The container was never created.
|
||||
catch (\OpenStack\Transport\FileNotFoundException $e) {
|
||||
return;
|
||||
self::$httpClient = new self::$settings['transport']($options);
|
||||
}
|
||||
|
||||
return self::$httpClient;
|
||||
}
|
||||
|
||||
foreach ($container as $object) {
|
||||
try {
|
||||
$container->delete($object->name());
|
||||
}
|
||||
catch (\Exception $e) {}
|
||||
/**
|
||||
* Destroy a container fixture.
|
||||
*
|
||||
* This should be called in any method that uses containerFixture().
|
||||
*/
|
||||
protected function destroyContainerFixture()
|
||||
{
|
||||
$store = $this->objectStore();
|
||||
$cname = self::$settings['openstack.swift.container'];
|
||||
|
||||
try {
|
||||
$container = $store->container($cname);
|
||||
}
|
||||
// The container was never created.
|
||||
catch (\OpenStack\Transport\FileNotFoundException $e) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($container as $object) {
|
||||
try {
|
||||
$container->delete($object->name());
|
||||
} catch (\Exception $e) {
|
||||
syslog(LOG_WARNING, $e);
|
||||
}
|
||||
}
|
||||
|
||||
$store->deleteContainer($cname);
|
||||
}
|
||||
|
||||
$store->deleteContainer($cname);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the HTTP Transport Client
|
||||
*
|
||||
* @return \OpenStack\Transport\ClientInterface A transport client.
|
||||
*/
|
||||
public static function getTransportClient() {
|
||||
|
||||
if (is_null(self::$httpClient)) {
|
||||
$options = [];
|
||||
if (isset(self::$settings['transport.proxy'])) {
|
||||
$options['proxy'] = self::$settings['transport.proxy'];
|
||||
}
|
||||
if (isset(self::$settings['transport.debug'])) {
|
||||
$options['debug'] = self::$settings['transport.debug'];
|
||||
}
|
||||
if (isset(self::$settings['transport.ssl.verify'])) {
|
||||
$options['ssl_verify'] = self::$settings['transport.ssl.verify'];
|
||||
}
|
||||
if (isset(self::$settings['transport.timeout'])) {
|
||||
$options['timeout'] = self::$settings['transport.timeout'];
|
||||
}
|
||||
|
||||
self::$httpClient = new self::$settings['transport']($options);
|
||||
}
|
||||
|
||||
return self::$httpClient;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy a container fixture.
|
||||
*
|
||||
* This should be called in any method that uses containerFixture().
|
||||
*/
|
||||
protected function destroyContainerFixture() {
|
||||
$store = $this->objectStore();
|
||||
$cname = self::$settings['openstack.swift.container'];
|
||||
|
||||
try {
|
||||
$container = $store->container($cname);
|
||||
}
|
||||
// The container was never created.
|
||||
catch (\OpenStack\Transport\FileNotFoundException $e) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($container as $object) {
|
||||
try {
|
||||
$container->delete($object->name());
|
||||
}
|
||||
catch (\Exception $e) {
|
||||
syslog(LOG_WARNING, $e);
|
||||
}
|
||||
}
|
||||
|
||||
$store->deleteContainer($cname);
|
||||
}
|
||||
}
|
||||
|
@ -2,17 +2,17 @@
|
||||
/* ============================================================================
|
||||
(c) Copyright 2012-2014 Hewlett-Packard Development Company, L.P.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
============================================================================ */
|
||||
/**
|
||||
* Unit tests for ObjectStorage ACLs.
|
||||
@ -25,182 +25,193 @@ use \OpenStack\Storage\ObjectStorage\ACL;
|
||||
/**
|
||||
* @ingroup Tests
|
||||
*/
|
||||
class ACLTest extends \OpenStack\Tests\TestCase {
|
||||
class ACLTest extends \OpenStack\Tests\TestCase
|
||||
{
|
||||
public function testConstructor()
|
||||
{
|
||||
$acl = new ACL();
|
||||
$this->assertEmpty($acl->rules());
|
||||
|
||||
public function testConstructor() {
|
||||
$acl = new ACL();
|
||||
$this->assertEmpty($acl->rules());
|
||||
}
|
||||
|
||||
}
|
||||
public function testAddAccount()
|
||||
{
|
||||
$acl = new ACL();
|
||||
|
||||
public function testAddAccount() {
|
||||
$acl = new ACL();
|
||||
$acl->addAccount(ACL::READ, 'test');
|
||||
|
||||
$acl->addAccount(ACL::READ, 'test');
|
||||
$rules = $acl->rules();
|
||||
|
||||
$rules = $acl->rules();
|
||||
$this->assertEquals(1, count($rules));
|
||||
|
||||
$this->assertEquals(1, count($rules));
|
||||
$rule = array_shift($rules);
|
||||
|
||||
$rule = array_shift($rules);
|
||||
$this->assertEquals(ACL::READ, $rule['mask']);
|
||||
$this->assertEquals('test', $rule['account']);
|
||||
|
||||
$this->assertEquals(ACL::READ, $rule['mask']);
|
||||
$this->assertEquals('test', $rule['account']);
|
||||
// Test with user
|
||||
$acl = new ACL();
|
||||
$acl->addAccount(ACL::WRITE, 'admin', 'earnie');
|
||||
$rules = $acl->rules();
|
||||
$rule = array_shift($rules);
|
||||
|
||||
// Test with user
|
||||
$acl = new ACL();
|
||||
$acl->addAccount(ACL::WRITE, 'admin', 'earnie');
|
||||
$rules = $acl->rules();
|
||||
$rule = array_shift($rules);
|
||||
$this->assertEquals(ACL::WRITE, $rule['mask']);
|
||||
$this->assertEquals('admin', $rule['account']);
|
||||
$this->assertEquals('earnie', $rule['user']);
|
||||
|
||||
$this->assertEquals(ACL::WRITE, $rule['mask']);
|
||||
$this->assertEquals('admin', $rule['account']);
|
||||
$this->assertEquals('earnie', $rule['user']);
|
||||
// Test with multiple users:
|
||||
$acl = new ACL();
|
||||
$acl->addAccount(ACL::WRITE, 'admin', array('earnie', 'bert'));
|
||||
$rules = $acl->rules();
|
||||
$rule = array_shift($rules);
|
||||
|
||||
// Test with multiple users:
|
||||
$acl = new ACL();
|
||||
$acl->addAccount(ACL::WRITE, 'admin', array('earnie', 'bert'));
|
||||
$rules = $acl->rules();
|
||||
$rule = array_shift($rules);
|
||||
$this->assertEquals(ACL::WRITE, $rule['mask']);
|
||||
$this->assertEquals('admin', $rule['account']);
|
||||
$this->assertEquals('earnie', $rule['user'][0]);
|
||||
$this->assertEquals('bert', $rule['user'][1]);
|
||||
|
||||
$this->assertEquals(ACL::WRITE, $rule['mask']);
|
||||
$this->assertEquals('admin', $rule['account']);
|
||||
$this->assertEquals('earnie', $rule['user'][0]);
|
||||
$this->assertEquals('bert', $rule['user'][1]);
|
||||
}
|
||||
|
||||
}
|
||||
public function testAddReferrer()
|
||||
{
|
||||
$acl = new ACL();
|
||||
$acl->addReferrer(ACL::READ, '.example.com');
|
||||
$acl->addReferrer(ACL::READ_WRITE, '-bad.example.com');
|
||||
|
||||
public function testAddReferrer() {
|
||||
$acl = new ACL();
|
||||
$acl->addReferrer(ACL::READ, '.example.com');
|
||||
$acl->addReferrer(ACL::READ_WRITE, '-bad.example.com');
|
||||
$rules = $acl->rules();
|
||||
|
||||
$rules = $acl->rules();
|
||||
$this->assertEquals(2, count($rules));
|
||||
|
||||
$this->assertEquals(2, count($rules));
|
||||
$first = array_shift($rules);
|
||||
$this->assertEquals(ACL::READ, $first['mask']);
|
||||
$this->assertEquals('.example.com', $first['host']);
|
||||
}
|
||||
|
||||
$first = array_shift($rules);
|
||||
$this->assertEquals(ACL::READ, $first['mask']);
|
||||
$this->assertEquals('.example.com', $first['host']);
|
||||
}
|
||||
public function testAllowListings()
|
||||
{
|
||||
$acl = new ACL();
|
||||
$acl->allowListings();
|
||||
$rules = $acl->rules();
|
||||
|
||||
public function testAllowListings() {
|
||||
$acl = new ACL();
|
||||
$acl->allowListings();
|
||||
$rules = $acl->rules();
|
||||
$this->assertEquals(1, count($rules));
|
||||
$this->assertTrue($rules[0]['rlistings']);
|
||||
$this->assertEquals(ACL::READ, $rules[0]['mask']);
|
||||
}
|
||||
|
||||
$this->assertEquals(1, count($rules));
|
||||
$this->assertTrue($rules[0]['rlistings']);
|
||||
$this->assertEquals(ACL::READ, $rules[0]['mask']);
|
||||
}
|
||||
public function testHeaders()
|
||||
{
|
||||
$acl = new ACL();
|
||||
$acl->addAccount(ACL::READ_WRITE, 'test');
|
||||
|
||||
public function testHeaders() {
|
||||
$acl = new ACL();
|
||||
$acl->addAccount(ACL::READ_WRITE, 'test');
|
||||
$headers = $acl->headers();
|
||||
|
||||
$headers = $acl->headers();
|
||||
$this->assertEquals(2, count($headers));
|
||||
$read = $headers[ACL::HEADER_READ];
|
||||
$write = $headers[ACL::HEADER_WRITE];
|
||||
|
||||
$this->assertEquals(2, count($headers));
|
||||
$read = $headers[ACL::HEADER_READ];
|
||||
$write = $headers[ACL::HEADER_WRITE];
|
||||
$this->assertEquals('test', $read);
|
||||
$this->assertEquals('test', $write);
|
||||
|
||||
$this->assertEquals('test', $read);
|
||||
$this->assertEquals('test', $write);
|
||||
// Test hostname rules, which should only appear in READ.
|
||||
$acl = new ACL();
|
||||
$acl->addReferrer(ACL::READ_WRITE, '.example.com');
|
||||
$headers = $acl->headers();
|
||||
|
||||
// Test hostname rules, which should only appear in READ.
|
||||
$acl = new ACL();
|
||||
$acl->addReferrer(ACL::READ_WRITE, '.example.com');
|
||||
$headers = $acl->headers();
|
||||
$this->assertEquals(1, count($headers), print_r($headers, TRUE));
|
||||
$read = $headers[ACL::HEADER_READ];
|
||||
|
||||
$this->assertEquals(1, count($headers), print_r($headers, TRUE));
|
||||
$read = $headers[ACL::HEADER_READ];
|
||||
$this->assertEquals('.r:.example.com', $read);
|
||||
}
|
||||
|
||||
$this->assertEquals('.r:.example.com', $read);
|
||||
}
|
||||
public function testToString()
|
||||
{
|
||||
$acl = new ACL();
|
||||
$acl->addReferrer(ACL::READ_WRITE, '.example.com');
|
||||
|
||||
public function testToString() {
|
||||
$acl = new ACL();
|
||||
$acl->addReferrer(ACL::READ_WRITE, '.example.com');
|
||||
$str = (string) $acl;
|
||||
|
||||
$str = (string) $acl;
|
||||
$this->assertEquals('X-Container-Read: .r:.example.com', $str);
|
||||
}
|
||||
|
||||
$this->assertEquals('X-Container-Read: .r:.example.com', $str);
|
||||
}
|
||||
public function testMakePublic()
|
||||
{
|
||||
$acl = (string) ACL::makePublic();
|
||||
|
||||
public function testMakePublic() {
|
||||
$acl = (string) ACL::makePublic();
|
||||
$this->assertEquals('X-Container-Read: .r:*,.rlistings', $acl);
|
||||
}
|
||||
|
||||
$this->assertEquals('X-Container-Read: .r:*,.rlistings', $acl);
|
||||
}
|
||||
public function testMakeNonPublic()
|
||||
{
|
||||
$acl = (string) ACL::makeNonPublic();
|
||||
|
||||
public function testMakeNonPublic() {
|
||||
$acl = (string) ACL::makeNonPublic();
|
||||
$this->assertEmpty($acl);
|
||||
}
|
||||
|
||||
$this->assertEmpty($acl);
|
||||
}
|
||||
public function testNewFromHeaders()
|
||||
{
|
||||
$headers = array(
|
||||
ACL::HEADER_READ => '.r:.example.com,.rlistings,.r:-*.evil.net',
|
||||
ACL::HEADER_WRITE => 'testact2, testact3:earnie, .rlistings ',
|
||||
);
|
||||
|
||||
public function testNewFromHeaders() {
|
||||
$headers = array(
|
||||
ACL::HEADER_READ => '.r:.example.com,.rlistings,.r:-*.evil.net',
|
||||
ACL::HEADER_WRITE => 'testact2, testact3:earnie, .rlistings ',
|
||||
);
|
||||
$acl = ACL::newFromHeaders($headers);
|
||||
|
||||
$acl = ACL::newFromHeaders($headers);
|
||||
$rules = $acl->rules();
|
||||
|
||||
$rules = $acl->rules();
|
||||
$this->assertEquals(6, count($rules));
|
||||
|
||||
$this->assertEquals(6, count($rules));
|
||||
// Yay, now we get to test each one.
|
||||
|
||||
// Yay, now we get to test each one.
|
||||
$this->assertEquals(ACL::READ, $rules[0]['mask']);
|
||||
$this->assertEquals('.example.com', $rules[0]['host']);
|
||||
$this->assertTrue($rules[1]['rlistings']);
|
||||
$this->assertEquals('-*.evil.net', $rules[2]['host']);
|
||||
|
||||
$this->assertEquals(ACL::READ, $rules[0]['mask']);
|
||||
$this->assertEquals('.example.com', $rules[0]['host']);
|
||||
$this->assertTrue($rules[1]['rlistings']);
|
||||
$this->assertEquals('-*.evil.net', $rules[2]['host']);
|
||||
$this->assertEquals(ACL::WRITE, $rules[3]['mask']);
|
||||
$this->assertEquals('testact2', $rules[3]['account']);
|
||||
$this->assertEquals('testact3', $rules[4]['account']);
|
||||
$this->assertEquals('earnie', $rules[4]['user']);
|
||||
$this->assertTrue($rules[5]['rlistings']);
|
||||
|
||||
$this->assertEquals(ACL::WRITE, $rules[3]['mask']);
|
||||
$this->assertEquals('testact2', $rules[3]['account']);
|
||||
$this->assertEquals('testact3', $rules[4]['account']);
|
||||
$this->assertEquals('earnie', $rules[4]['user']);
|
||||
$this->assertTrue($rules[5]['rlistings']);
|
||||
// Final canary:
|
||||
$headers = $acl->headers();
|
||||
$read = $headers[ACL::HEADER_READ];
|
||||
$write = $headers[ACL::HEADER_WRITE];
|
||||
|
||||
// Final canary:
|
||||
$headers = $acl->headers();
|
||||
$read = $headers[ACL::HEADER_READ];
|
||||
$write = $headers[ACL::HEADER_WRITE];
|
||||
$this->assertEquals('.r:.example.com,.rlistings,.r:-*.evil.net', $read);
|
||||
// Note that the spurious .rlistings was removed.
|
||||
$this->assertEquals('testact2,testact3:earnie', $write);
|
||||
|
||||
$this->assertEquals('.r:.example.com,.rlistings,.r:-*.evil.net', $read);
|
||||
// Note that the spurious .rlistings was removed.
|
||||
$this->assertEquals('testact2,testact3:earnie', $write);
|
||||
}
|
||||
|
||||
}
|
||||
public function testIsNonPublic()
|
||||
{
|
||||
$acl = new ACL();
|
||||
|
||||
public function testIsNonPublic() {
|
||||
$acl = new ACL();
|
||||
$this->assertTrue($acl->isNonPublic());
|
||||
|
||||
$this->assertTrue($acl->isNonPublic());
|
||||
$acl->addReferrer(ACL::READ, '*.evil.net');
|
||||
$this->assertFalse($acl->isNonPublic());
|
||||
|
||||
$acl->addReferrer(ACL::READ, '*.evil.net');
|
||||
$this->assertFalse($acl->isNonPublic());
|
||||
$acl = ACL::makeNonPublic();
|
||||
$this->assertTrue($acl->isNonPublic());
|
||||
}
|
||||
|
||||
$acl = ACL::makeNonPublic();
|
||||
$this->assertTrue($acl->isNonPublic());
|
||||
}
|
||||
public function testIsPublic()
|
||||
{
|
||||
$acl = new ACL();
|
||||
|
||||
public function testIsPublic() {
|
||||
$acl = new ACL();
|
||||
$this->assertFalse($acl->isPublic());
|
||||
$acl->allowListings();
|
||||
$acl->addReferrer(ACL::READ, '*');
|
||||
|
||||
$this->assertFalse($acl->isPublic());
|
||||
$acl->allowListings();
|
||||
$acl->addReferrer(ACL::READ, '*');
|
||||
$this->assertTrue($acl->isPublic());
|
||||
|
||||
$this->assertTrue($acl->isPublic());
|
||||
$acl->addAccount(ACL::WRITE, 'foo', 'bar');
|
||||
$this->assertTrue($acl->isPublic());
|
||||
|
||||
$acl->addAccount(ACL::WRITE, 'foo', 'bar');
|
||||
$this->assertTrue($acl->isPublic());
|
||||
|
||||
$acl = ACL::makePublic();
|
||||
$this->assertTrue($acl->isPublic());
|
||||
}
|
||||
$acl = ACL::makePublic();
|
||||
$this->assertTrue($acl->isPublic());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -2,17 +2,17 @@
|
||||
/* ============================================================================
|
||||
(c) Copyright 2014 Hewlett-Packard Development Company, L.P.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
============================================================================ */
|
||||
/**
|
||||
* Unit tests for the Autoloader.
|
||||
@ -22,25 +22,27 @@ namespace OpenStack\Tests;
|
||||
require_once 'src/OpenStack/Autoloader.php';
|
||||
require_once 'test/TestCase.php';
|
||||
|
||||
class AutoloaderTest extends \OpenStack\Tests\TestCase {
|
||||
class AutoloaderTest extends \OpenStack\Tests\TestCase
|
||||
{
|
||||
/**
|
||||
* Test the BaseDir.
|
||||
*/
|
||||
public function testBasedir()
|
||||
{
|
||||
$basedir = \OpenStack\Autoloader::$basedir;
|
||||
$this->assertRegExp('/OpenStack/', $basedir);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the BaseDir.
|
||||
*/
|
||||
public function testBasedir() {
|
||||
$basedir = \OpenStack\Autoloader::$basedir;
|
||||
$this->assertRegExp('/OpenStack/', $basedir);
|
||||
}
|
||||
/**
|
||||
* Test the autoloader.
|
||||
*/
|
||||
public function testAutoloader()
|
||||
{
|
||||
\OpenStack\Autoloader::useAutoloader();
|
||||
|
||||
/**
|
||||
* Test the autoloader.
|
||||
*/
|
||||
public function testAutoloader() {
|
||||
\OpenStack\Autoloader::useAutoloader();
|
||||
// If we can construct a class, we are okay.
|
||||
$test = new \OpenStack\Exception("TEST");
|
||||
|
||||
// If we can construct a class, we are okay.
|
||||
$test = new \OpenStack\Exception("TEST");
|
||||
|
||||
$this->assertInstanceOf('\OpenStack\Exception', $test);
|
||||
}
|
||||
$this->assertInstanceOf('\OpenStack\Exception', $test);
|
||||
}
|
||||
}
|
||||
|
@ -2,17 +2,17 @@
|
||||
/* ============================================================================
|
||||
(c) Copyright 2012-2014 Hewlett-Packard Development Company, L.P.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
============================================================================ */
|
||||
/**
|
||||
* Unit tests for the Bootstrap.
|
||||
@ -21,12 +21,13 @@ namespace OpenStack\Tests;
|
||||
|
||||
require_once 'test/TestCase.php';
|
||||
|
||||
class BootstrapTest extends \OpenStack\Tests\TestCase {
|
||||
|
||||
/**
|
||||
* Canary test.
|
||||
*/
|
||||
public function testSettings() {
|
||||
$this->assertTrue(!empty(self::$settings));
|
||||
}
|
||||
class BootstrapTest extends \OpenStack\Tests\TestCase
|
||||
{
|
||||
/**
|
||||
* Canary test.
|
||||
*/
|
||||
public function testSettings()
|
||||
{
|
||||
$this->assertTrue(!empty(self::$settings));
|
||||
}
|
||||
}
|
||||
|
@ -2,17 +2,17 @@
|
||||
/* ============================================================================
|
||||
(c) Copyright 2012-2014 Hewlett-Packard Development Company, L.P.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
============================================================================ */
|
||||
/**
|
||||
* Unit tests for Containers.
|
||||
@ -25,414 +25,423 @@ use \OpenStack\Storage\ObjectStorage\Container;
|
||||
use \OpenStack\Storage\ObjectStorage\Object;
|
||||
use \OpenStack\Storage\ObjectStorage\ACL;
|
||||
|
||||
class ContainerTest extends \OpenStack\Tests\TestCase {
|
||||
class ContainerTest extends \OpenStack\Tests\TestCase
|
||||
{
|
||||
const FILENAME = 'unit-test-dummy.txt';
|
||||
const FILESTR = 'This is a test.';
|
||||
|
||||
const FILENAME = 'unit-test-dummy.txt';
|
||||
const FILESTR = 'This is a test.';
|
||||
// The factory functions (newFrom*) are tested in the
|
||||
// ObjectStorage tests, as they are required there.
|
||||
// Rather than build a Mock to achieve the same test here,
|
||||
// we just don't test them again.
|
||||
|
||||
// The factory functions (newFrom*) are tested in the
|
||||
// ObjectStorage tests, as they are required there.
|
||||
// Rather than build a Mock to achieve the same test here,
|
||||
// we just don't test them again.
|
||||
public function testConstructor()
|
||||
{
|
||||
$container = new Container('foo');
|
||||
$this->assertEquals('foo', $container->name());
|
||||
|
||||
public function testConstructor() {
|
||||
$container = new Container('foo');
|
||||
$this->assertEquals('foo', $container->name());
|
||||
|
||||
// These will now cause the system to try to fetch a remote
|
||||
// container.
|
||||
//$this->assertEquals(0, $container->bytes());
|
||||
//$this->assertEquals(0, $container->count());
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \OpenStack\Exception
|
||||
*/
|
||||
public function testConstructorFailure() {
|
||||
$container = new Container('foo');
|
||||
$this->assertEquals('foo', $container->name());
|
||||
|
||||
// These will now cause the system to try to fetch a remote
|
||||
// container. This is a failure condition.
|
||||
$this->assertEquals(0, $container->bytes());
|
||||
}
|
||||
|
||||
public function testCountable() {
|
||||
// Verify that the interface Countable is properly
|
||||
// implemented.
|
||||
|
||||
$mockJSON = array('count' => 5, 'bytes' => 128, 'name' => 'foo');
|
||||
|
||||
$container = Container::newFromJSON($mockJSON, 'fake', 'fake');
|
||||
|
||||
$this->assertEquals(5, count($container));
|
||||
|
||||
}
|
||||
|
||||
const FNAME = 'testSave';
|
||||
const FCONTENT = 'This is a test.';
|
||||
const FTYPE = 'application/x-monkey-file';
|
||||
|
||||
public function testSave() {
|
||||
|
||||
// Clean up anything left.
|
||||
$this->destroyContainerFixture();
|
||||
|
||||
$container = $this->containerFixture();
|
||||
|
||||
$obj = new Object(self::FNAME, self::FCONTENT, self::FTYPE);
|
||||
$obj->setMetadata(array('foo' => '1234'));
|
||||
|
||||
$this->assertEquals(self::FCONTENT, $obj->content());
|
||||
|
||||
try {
|
||||
$ret = $container->save($obj);
|
||||
}
|
||||
catch (\Exception $e) {
|
||||
$this->destroyContainerFixture();
|
||||
throw $e;
|
||||
// These will now cause the system to try to fetch a remote
|
||||
// container.
|
||||
//$this->assertEquals(0, $container->bytes());
|
||||
//$this->assertEquals(0, $container->count());
|
||||
}
|
||||
|
||||
$this->assertTrue($ret);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testSave
|
||||
*/
|
||||
public function testRemoteObject() {
|
||||
$container = $this->containerFixture();
|
||||
$object = $container->remoteObject(self::FNAME);
|
||||
|
||||
$this->assertEquals(self::FNAME, $object->name());
|
||||
$this->assertEquals(self::FTYPE, $object->contentType());
|
||||
|
||||
$etag = md5(self::FCONTENT);
|
||||
$this->assertEquals($etag, $object->eTag());
|
||||
|
||||
$md = $object->metadata();
|
||||
$this->assertEquals(1, count($md));
|
||||
|
||||
// Note that headers are normalized remotely to have initial
|
||||
// caps. Since we have no way of knowing what the original
|
||||
// metadata casing is, we leave it with initial caps.
|
||||
$this->assertEquals('1234', $md['Foo']);
|
||||
|
||||
$content = $object->content();
|
||||
$this->assertEquals(self::FCONTENT, $content);
|
||||
|
||||
// Make sure I can do this twice (regression).
|
||||
// Note that this SHOULD perform another request.
|
||||
$this->assertEquals(self::FCONTENT, $object->content());
|
||||
|
||||
// Overwrite the copy:
|
||||
$object->setContent('HI');
|
||||
$this->assertEquals('HI', $object->content());
|
||||
|
||||
// Make sure I can do this twice (regression check).
|
||||
$this->assertEquals('HI', $object->content());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @depends testRemoteObject
|
||||
*/
|
||||
public function testRefresh() {
|
||||
$container = $this->containerFixture();
|
||||
$object = $container->remoteObject(self::FNAME);
|
||||
|
||||
$content = (string) $object->content();
|
||||
$object->setContent('FOO');
|
||||
$this->assertEquals('FOO', $object->content());
|
||||
|
||||
$object->refresh(TRUE);
|
||||
$this->assertEquals($content, (string) $object->content());
|
||||
|
||||
$object->refresh(FALSE);
|
||||
$this->assertEquals($content, (string) $object->content());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testRemoteObject
|
||||
*/
|
||||
public function testObject() {
|
||||
$container = $this->containerFixture();
|
||||
$object = $container->object(self::FNAME);
|
||||
|
||||
$this->assertEquals(self::FNAME, $object->name());
|
||||
$this->assertEquals(self::FTYPE, $object->contentType());
|
||||
|
||||
$etag = md5(self::FCONTENT);
|
||||
$this->assertEquals($etag, $object->eTag());
|
||||
|
||||
$md = $object->metadata();
|
||||
$this->assertEquals(1, count($md));
|
||||
|
||||
// Note that headers are normalized remotely to have initial
|
||||
// caps. Since we have no way of knowing what the original
|
||||
// metadata casing is, we leave it with initial caps.
|
||||
$this->assertEquals('1234', $md['Foo']);
|
||||
|
||||
$content = $object->content();
|
||||
|
||||
$this->assertEquals(self::FCONTENT, $content);
|
||||
|
||||
// Overwrite the copy:
|
||||
$object->setContent('HI');
|
||||
$this->assertEquals('HI', $object->content());
|
||||
|
||||
// Make sure this throws a 404.
|
||||
try {
|
||||
$foo = $container->object('no/such');
|
||||
}
|
||||
catch (\OpenStack\Exception $e) {
|
||||
$this->assertInstanceOf('\OpenStack\Transport\FileNotFoundException', $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testSave
|
||||
*/
|
||||
public function testObjects() {
|
||||
$container = $this->containerFixture();
|
||||
$obj1 = new Object('a/' . self::FNAME, self::FCONTENT, self::FTYPE);
|
||||
$obj2 = new Object('a/b/' . self::FNAME, self::FCONTENT, self::FTYPE);
|
||||
|
||||
$container->save($obj1);
|
||||
$container->save($obj2);
|
||||
|
||||
// Now we have a container with three items.
|
||||
$objects = $container->objects();
|
||||
|
||||
$this->assertEquals(3, count($objects));
|
||||
|
||||
$objects = $container->objects(1, 'a/' . self::FNAME);
|
||||
|
||||
$this->assertEquals(1, count($objects));
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testObjects
|
||||
*/
|
||||
public function testGetIterator() {
|
||||
|
||||
$container = $this->containerFixture();
|
||||
|
||||
$it = $container->getIterator();
|
||||
$this->assertInstanceOf('Traversable', $it);
|
||||
|
||||
$i = 0;
|
||||
foreach ($container as $item) {
|
||||
++$i;
|
||||
}
|
||||
$this->assertEquals(3, $i);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testObjects
|
||||
*/
|
||||
public function testObjectsWithPrefix() {
|
||||
$container = $this->containerFixture();
|
||||
|
||||
$objects = $container->objectsWithPrefix('a/');
|
||||
$this->assertEquals(2, count($objects));
|
||||
|
||||
foreach ($objects as $o) {
|
||||
if ($o instanceof Object) {
|
||||
$this->assertEquals('a/' . self::FNAME, $o->name());
|
||||
}
|
||||
else {
|
||||
$this->assertEquals('a/b/', $o->path());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Since we set the delimiter to ':' we will get back
|
||||
// all of the objects in a/. This is because none of
|
||||
// the objects contain ':' in their names.
|
||||
$objects = $container->objectsWithPrefix('a/', ':');
|
||||
$this->assertEquals(2, count($objects));
|
||||
|
||||
foreach ($objects as $o) {
|
||||
$this->assertInstanceOf('\OpenStack\Storage\ObjectStorage\Object', $o);
|
||||
}
|
||||
|
||||
// This should give us one file and one subdir.
|
||||
$objects = $container->objectsWithPrefix('', '/');
|
||||
$this->assertEquals(2, count($objects));
|
||||
|
||||
foreach ($objects as $o) {
|
||||
if ($o instanceof Object) {
|
||||
$this->assertEquals(self::FNAME, $o->name());
|
||||
}
|
||||
else {
|
||||
$this->assertEquals('a/', $o->path());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testObjects
|
||||
*/
|
||||
public function testObjectsWithPath() {
|
||||
$container = $this->containerFixture();
|
||||
$objects = $container->objectsByPath('a/b/');
|
||||
|
||||
$this->assertEquals(1, count($objects));
|
||||
|
||||
$o = array_shift($objects);
|
||||
$this->assertEquals('a/b/' . self::FNAME, $o->name());
|
||||
|
||||
/*
|
||||
* The Open Stack documentation is unclear about how best to
|
||||
* use paths. Experimentation suggests that if you rely on paths
|
||||
* instead of prefixes, your best bet is to create directory
|
||||
* markers.
|
||||
/**
|
||||
* @expectedException \OpenStack\Exception
|
||||
*/
|
||||
public function testConstructorFailure()
|
||||
{
|
||||
$container = new Container('foo');
|
||||
$this->assertEquals('foo', $container->name());
|
||||
|
||||
// Test subdir listings:
|
||||
// This does not work (by design?) with Path. You have to use prefix
|
||||
// or else create directory markers.
|
||||
// $obj1 = new Object('a/aa/aaa/' . self::FNAME, self::FCONTENT, self::FTYPE);
|
||||
// $container->save($obj1);
|
||||
// $objects = $container->objectsByPath('a/aaa', '/');
|
||||
|
||||
// $this->assertEquals(1, count($objects), 'One subdir');
|
||||
|
||||
// $objects = $container->objectsByPath('a/');
|
||||
// throw new \Exception(print_r($objects, TRUE));
|
||||
// $this->assertEquals(2, count($objects));
|
||||
|
||||
// foreach ($objects as $o) {
|
||||
// if ($o instanceof Object) {
|
||||
// $this->assertEquals('a/' . self::FNAME, $o->name());
|
||||
// }
|
||||
// else {
|
||||
// $this->assertEquals('a/b/', $o->path());
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testRemoteObject
|
||||
*/
|
||||
public function testUpdateMetadata() {
|
||||
$container = $this->containerFixture();
|
||||
$object = $container->remoteObject(self::FNAME);
|
||||
|
||||
$md = $object->metadata();
|
||||
|
||||
$this->assertEquals('1234', $md['Foo']);
|
||||
|
||||
$md['Foo'] = 456;
|
||||
$md['Bar'] = 'bert';
|
||||
$object->setMetadata($md);
|
||||
|
||||
$container->updateMetadata($object);
|
||||
|
||||
$copy = $container->remoteObject(self::FNAME);
|
||||
|
||||
$this->assertEquals('456', $md['Foo']);
|
||||
$this->assertEquals('bert', $md['Bar']);
|
||||
|
||||
// Now we need to canary test:
|
||||
$this->assertEquals($object->contentType(), $copy->contentType());
|
||||
$this->assertEquals($object->contentLength(), $copy->contentLength());
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testRemoteObject
|
||||
*/
|
||||
public function testCopy() {
|
||||
$container = $this->containerFixture();
|
||||
$object = $container->remoteObject(self::FNAME);
|
||||
|
||||
$container->copy($object, 'FOO-1.txt');
|
||||
|
||||
$copy = $container->remoteObject('FOO-1.txt');
|
||||
|
||||
$this->assertEquals($object->contentType(), $copy->contentType());
|
||||
$this->assertEquals($object->etag(), $copy->etag());
|
||||
|
||||
$container->delete('foo-1.txt');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testCopy
|
||||
*/
|
||||
public function testCopyAcrossContainers() {
|
||||
|
||||
// Create a new container.
|
||||
$store = $this->objectStore();
|
||||
$cname = self::$settings['openstack.swift.container'] . 'COPY';
|
||||
if ($store->hasContainer($cname)) {
|
||||
$this->eradicateContainer($cname);
|
||||
// These will now cause the system to try to fetch a remote
|
||||
// container. This is a failure condition.
|
||||
$this->assertEquals(0, $container->bytes());
|
||||
}
|
||||
|
||||
$store->createContainer($cname);
|
||||
$newContainer = $store->container($cname);
|
||||
public function testCountable()
|
||||
{
|
||||
// Verify that the interface Countable is properly
|
||||
// implemented.
|
||||
|
||||
// Get teh old container and its object.
|
||||
$container = $this->containerFixture();
|
||||
$object = $container->remoteObject(self::FNAME);
|
||||
$mockJSON = array('count' => 5, 'bytes' => 128, 'name' => 'foo');
|
||||
|
||||
$ret = $container->copy($object, 'foo-1.txt', $cname);
|
||||
$container = Container::newFromJSON($mockJSON, 'fake', 'fake');
|
||||
|
||||
$this->assertTrue($ret);
|
||||
$this->assertEquals(5, count($container));
|
||||
|
||||
$copy = $newContainer->remoteObject('foo-1.txt');
|
||||
|
||||
$this->assertEquals($object->etag(), $copy->etag());
|
||||
|
||||
$this->eradicateContainer($cname);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @depends testSave
|
||||
*/
|
||||
public function testDelete() {
|
||||
$container = $this->containerFixture();
|
||||
|
||||
$ret = $container->delete(self::FNAME);
|
||||
|
||||
$fail = $container->delete('no_such_file.txt');
|
||||
|
||||
$this->destroyContainerFixture();
|
||||
$this->assertTrue($ret);
|
||||
$this->assertFalse($fail);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @group public
|
||||
*/
|
||||
public function testAcl() {
|
||||
$store = $this->objectStore();
|
||||
$cname = self::$settings['openstack.swift.container'] . 'PUBLIC';
|
||||
|
||||
if ($store->hasContainer($cname)) {
|
||||
$store->deleteContainer($cname);
|
||||
}
|
||||
|
||||
$store->createContainer($cname, ACL::makePublic());
|
||||
const FNAME = 'testSave';
|
||||
const FCONTENT = 'This is a test.';
|
||||
const FTYPE = 'application/x-monkey-file';
|
||||
|
||||
public function testSave()
|
||||
{
|
||||
// Clean up anything left.
|
||||
$this->destroyContainerFixture();
|
||||
|
||||
$container = $this->containerFixture();
|
||||
|
||||
$obj = new Object(self::FNAME, self::FCONTENT, self::FTYPE);
|
||||
$obj->setMetadata(array('foo' => '1234'));
|
||||
|
||||
$this->assertEquals(self::FCONTENT, $obj->content());
|
||||
|
||||
try {
|
||||
$ret = $container->save($obj);
|
||||
} catch (\Exception $e) {
|
||||
$this->destroyContainerFixture();
|
||||
throw $e;
|
||||
}
|
||||
|
||||
$this->assertTrue($ret);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testSave
|
||||
*/
|
||||
public function testRemoteObject()
|
||||
{
|
||||
$container = $this->containerFixture();
|
||||
$object = $container->remoteObject(self::FNAME);
|
||||
|
||||
$this->assertEquals(self::FNAME, $object->name());
|
||||
$this->assertEquals(self::FTYPE, $object->contentType());
|
||||
|
||||
$etag = md5(self::FCONTENT);
|
||||
$this->assertEquals($etag, $object->eTag());
|
||||
|
||||
$md = $object->metadata();
|
||||
$this->assertEquals(1, count($md));
|
||||
|
||||
// Note that headers are normalized remotely to have initial
|
||||
// caps. Since we have no way of knowing what the original
|
||||
// metadata casing is, we leave it with initial caps.
|
||||
$this->assertEquals('1234', $md['Foo']);
|
||||
|
||||
$content = $object->content();
|
||||
$this->assertEquals(self::FCONTENT, $content);
|
||||
|
||||
// Make sure I can do this twice (regression).
|
||||
// Note that this SHOULD perform another request.
|
||||
$this->assertEquals(self::FCONTENT, $object->content());
|
||||
|
||||
// Overwrite the copy:
|
||||
$object->setContent('HI');
|
||||
$this->assertEquals('HI', $object->content());
|
||||
|
||||
// Make sure I can do this twice (regression check).
|
||||
$this->assertEquals('HI', $object->content());
|
||||
}
|
||||
|
||||
|
||||
$store->containers();
|
||||
$container = $store->container($cname);
|
||||
/**
|
||||
* @depends testRemoteObject
|
||||
*/
|
||||
public function testRefresh()
|
||||
{
|
||||
$container = $this->containerFixture();
|
||||
$object = $container->remoteObject(self::FNAME);
|
||||
|
||||
$acl = $container->acl();
|
||||
$content = (string) $object->content();
|
||||
$object->setContent('FOO');
|
||||
$this->assertEquals('FOO', $object->content());
|
||||
|
||||
$this->assertInstanceOf('\OpenStack\Storage\ObjectStorage\ACL', $acl);
|
||||
$this->assertTrue($acl->isPublic());
|
||||
$object->refresh(TRUE);
|
||||
$this->assertEquals($content, (string) $object->content());
|
||||
|
||||
$store->deleteContainer($cname);
|
||||
$object->refresh(FALSE);
|
||||
$this->assertEquals($content, (string) $object->content());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testRemoteObject
|
||||
*/
|
||||
public function testObject()
|
||||
{
|
||||
$container = $this->containerFixture();
|
||||
$object = $container->object(self::FNAME);
|
||||
|
||||
$this->assertEquals(self::FNAME, $object->name());
|
||||
$this->assertEquals(self::FTYPE, $object->contentType());
|
||||
|
||||
$etag = md5(self::FCONTENT);
|
||||
$this->assertEquals($etag, $object->eTag());
|
||||
|
||||
$md = $object->metadata();
|
||||
$this->assertEquals(1, count($md));
|
||||
|
||||
// Note that headers are normalized remotely to have initial
|
||||
// caps. Since we have no way of knowing what the original
|
||||
// metadata casing is, we leave it with initial caps.
|
||||
$this->assertEquals('1234', $md['Foo']);
|
||||
|
||||
$content = $object->content();
|
||||
|
||||
$this->assertEquals(self::FCONTENT, $content);
|
||||
|
||||
// Overwrite the copy:
|
||||
$object->setContent('HI');
|
||||
$this->assertEquals('HI', $object->content());
|
||||
|
||||
// Make sure this throws a 404.
|
||||
try {
|
||||
$foo = $container->object('no/such');
|
||||
} catch (\OpenStack\Exception $e) {
|
||||
$this->assertInstanceOf('\OpenStack\Transport\FileNotFoundException', $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testSave
|
||||
*/
|
||||
public function testObjects()
|
||||
{
|
||||
$container = $this->containerFixture();
|
||||
$obj1 = new Object('a/' . self::FNAME, self::FCONTENT, self::FTYPE);
|
||||
$obj2 = new Object('a/b/' . self::FNAME, self::FCONTENT, self::FTYPE);
|
||||
|
||||
$container->save($obj1);
|
||||
$container->save($obj2);
|
||||
|
||||
// Now we have a container with three items.
|
||||
$objects = $container->objects();
|
||||
|
||||
$this->assertEquals(3, count($objects));
|
||||
|
||||
$objects = $container->objects(1, 'a/' . self::FNAME);
|
||||
|
||||
$this->assertEquals(1, count($objects));
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testObjects
|
||||
*/
|
||||
public function testGetIterator()
|
||||
{
|
||||
$container = $this->containerFixture();
|
||||
|
||||
$it = $container->getIterator();
|
||||
$this->assertInstanceOf('Traversable', $it);
|
||||
|
||||
$i = 0;
|
||||
foreach ($container as $item) {
|
||||
++$i;
|
||||
}
|
||||
$this->assertEquals(3, $i);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testObjects
|
||||
*/
|
||||
public function testObjectsWithPrefix()
|
||||
{
|
||||
$container = $this->containerFixture();
|
||||
|
||||
$objects = $container->objectsWithPrefix('a/');
|
||||
$this->assertEquals(2, count($objects));
|
||||
|
||||
foreach ($objects as $o) {
|
||||
if ($o instanceof Object) {
|
||||
$this->assertEquals('a/' . self::FNAME, $o->name());
|
||||
} else {
|
||||
$this->assertEquals('a/b/', $o->path());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Since we set the delimiter to ':' we will get back
|
||||
// all of the objects in a/. This is because none of
|
||||
// the objects contain ':' in their names.
|
||||
$objects = $container->objectsWithPrefix('a/', ':');
|
||||
$this->assertEquals(2, count($objects));
|
||||
|
||||
foreach ($objects as $o) {
|
||||
$this->assertInstanceOf('\OpenStack\Storage\ObjectStorage\Object', $o);
|
||||
}
|
||||
|
||||
// This should give us one file and one subdir.
|
||||
$objects = $container->objectsWithPrefix('', '/');
|
||||
$this->assertEquals(2, count($objects));
|
||||
|
||||
foreach ($objects as $o) {
|
||||
if ($o instanceof Object) {
|
||||
$this->assertEquals(self::FNAME, $o->name());
|
||||
} else {
|
||||
$this->assertEquals('a/', $o->path());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testObjects
|
||||
*/
|
||||
public function testObjectsWithPath()
|
||||
{
|
||||
$container = $this->containerFixture();
|
||||
$objects = $container->objectsByPath('a/b/');
|
||||
|
||||
$this->assertEquals(1, count($objects));
|
||||
|
||||
$o = array_shift($objects);
|
||||
$this->assertEquals('a/b/' . self::FNAME, $o->name());
|
||||
|
||||
/*
|
||||
* The Open Stack documentation is unclear about how best to
|
||||
* use paths. Experimentation suggests that if you rely on paths
|
||||
* instead of prefixes, your best bet is to create directory
|
||||
* markers.
|
||||
*/
|
||||
|
||||
// Test subdir listings:
|
||||
// This does not work (by design?) with Path. You have to use prefix
|
||||
// or else create directory markers.
|
||||
// $obj1 = new Object('a/aa/aaa/' . self::FNAME, self::FCONTENT, self::FTYPE);
|
||||
// $container->save($obj1);
|
||||
// $objects = $container->objectsByPath('a/aaa', '/');
|
||||
|
||||
// $this->assertEquals(1, count($objects), 'One subdir');
|
||||
|
||||
// $objects = $container->objectsByPath('a/');
|
||||
// throw new \Exception(print_r($objects, TRUE));
|
||||
// $this->assertEquals(2, count($objects));
|
||||
|
||||
// foreach ($objects as $o) {
|
||||
// if ($o instanceof Object) {
|
||||
// $this->assertEquals('a/' . self::FNAME, $o->name());
|
||||
// }
|
||||
// else {
|
||||
// $this->assertEquals('a/b/', $o->path());
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testRemoteObject
|
||||
*/
|
||||
public function testUpdateMetadata()
|
||||
{
|
||||
$container = $this->containerFixture();
|
||||
$object = $container->remoteObject(self::FNAME);
|
||||
|
||||
$md = $object->metadata();
|
||||
|
||||
$this->assertEquals('1234', $md['Foo']);
|
||||
|
||||
$md['Foo'] = 456;
|
||||
$md['Bar'] = 'bert';
|
||||
$object->setMetadata($md);
|
||||
|
||||
$container->updateMetadata($object);
|
||||
|
||||
$copy = $container->remoteObject(self::FNAME);
|
||||
|
||||
$this->assertEquals('456', $md['Foo']);
|
||||
$this->assertEquals('bert', $md['Bar']);
|
||||
|
||||
// Now we need to canary test:
|
||||
$this->assertEquals($object->contentType(), $copy->contentType());
|
||||
$this->assertEquals($object->contentLength(), $copy->contentLength());
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testRemoteObject
|
||||
*/
|
||||
public function testCopy()
|
||||
{
|
||||
$container = $this->containerFixture();
|
||||
$object = $container->remoteObject(self::FNAME);
|
||||
|
||||
$container->copy($object, 'FOO-1.txt');
|
||||
|
||||
$copy = $container->remoteObject('FOO-1.txt');
|
||||
|
||||
$this->assertEquals($object->contentType(), $copy->contentType());
|
||||
$this->assertEquals($object->etag(), $copy->etag());
|
||||
|
||||
$container->delete('foo-1.txt');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testCopy
|
||||
*/
|
||||
public function testCopyAcrossContainers()
|
||||
{
|
||||
// Create a new container.
|
||||
$store = $this->objectStore();
|
||||
$cname = self::$settings['openstack.swift.container'] . 'COPY';
|
||||
if ($store->hasContainer($cname)) {
|
||||
$this->eradicateContainer($cname);
|
||||
}
|
||||
|
||||
$store->createContainer($cname);
|
||||
$newContainer = $store->container($cname);
|
||||
|
||||
// Get teh old container and its object.
|
||||
$container = $this->containerFixture();
|
||||
$object = $container->remoteObject(self::FNAME);
|
||||
|
||||
$ret = $container->copy($object, 'foo-1.txt', $cname);
|
||||
|
||||
$this->assertTrue($ret);
|
||||
|
||||
$copy = $newContainer->remoteObject('foo-1.txt');
|
||||
|
||||
$this->assertEquals($object->etag(), $copy->etag());
|
||||
|
||||
$this->eradicateContainer($cname);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @depends testSave
|
||||
*/
|
||||
public function testDelete()
|
||||
{
|
||||
$container = $this->containerFixture();
|
||||
|
||||
$ret = $container->delete(self::FNAME);
|
||||
|
||||
$fail = $container->delete('no_such_file.txt');
|
||||
|
||||
$this->destroyContainerFixture();
|
||||
$this->assertTrue($ret);
|
||||
$this->assertFalse($fail);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @group public
|
||||
*/
|
||||
public function testAcl()
|
||||
{
|
||||
$store = $this->objectStore();
|
||||
$cname = self::$settings['openstack.swift.container'] . 'PUBLIC';
|
||||
|
||||
if ($store->hasContainer($cname)) {
|
||||
$store->deleteContainer($cname);
|
||||
}
|
||||
|
||||
$store->createContainer($cname, ACL::makePublic());
|
||||
|
||||
|
||||
$store->containers();
|
||||
$container = $store->container($cname);
|
||||
|
||||
$acl = $container->acl();
|
||||
|
||||
$this->assertInstanceOf('\OpenStack\Storage\ObjectStorage\ACL', $acl);
|
||||
$this->assertTrue($acl->isPublic());
|
||||
|
||||
$store->deleteContainer($cname);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -2,17 +2,17 @@
|
||||
/* ============================================================================
|
||||
(c) Copyright 2014 Hewlett-Packard Development Company, L.P.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
============================================================================ */
|
||||
|
||||
namespace OpenStack\Tests;
|
||||
@ -21,52 +21,55 @@ use OpenStack\Transport\GuzzleClient;
|
||||
|
||||
require_once 'test/TestCase.php';
|
||||
|
||||
class GuzzleClientTest extends \OpenStack\Tests\TestCase {
|
||||
class GuzzleClientTest extends \OpenStack\Tests\TestCase
|
||||
{
|
||||
/**
|
||||
* Get the config from the test settings file and pass that into the client.
|
||||
*/
|
||||
public function buildClient()
|
||||
{
|
||||
$options = array();
|
||||
if (isset(self::$settings['transport.proxy'])) {
|
||||
$options['proxy'] = self::$settings['transport.proxy'];
|
||||
}
|
||||
if (isset(self::$settings['transport.debug'])) {
|
||||
$options['debug'] = self::$settings['transport.debug'];
|
||||
}
|
||||
if (isset(self::$settings['transport.ssl.verify'])) {
|
||||
$options['ssl_verify'] = self::$settings['transport.ssl.verify'];
|
||||
}
|
||||
if (isset(self::$settings['transport.timeout'])) {
|
||||
$options['timeout'] = self::$settings['transport.timeout'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the config from the test settings file and pass that into the client.
|
||||
*/
|
||||
public function buildClient() {
|
||||
$options = array();
|
||||
if (isset(self::$settings['transport.proxy'])) {
|
||||
$options['proxy'] = self::$settings['transport.proxy'];
|
||||
}
|
||||
if (isset(self::$settings['transport.debug'])) {
|
||||
$options['debug'] = self::$settings['transport.debug'];
|
||||
}
|
||||
if (isset(self::$settings['transport.ssl.verify'])) {
|
||||
$options['ssl_verify'] = self::$settings['transport.ssl.verify'];
|
||||
}
|
||||
if (isset(self::$settings['transport.timeout'])) {
|
||||
$options['timeout'] = self::$settings['transport.timeout'];
|
||||
return new GuzzleClient($options);
|
||||
}
|
||||
|
||||
return new GuzzleClient($options);
|
||||
}
|
||||
public function testDoRequest()
|
||||
{
|
||||
$url = 'http://www.openstack.org';
|
||||
$method = 'GET';
|
||||
|
||||
public function testDoRequest() {
|
||||
$url = 'http://www.openstack.org';
|
||||
$method = 'GET';
|
||||
$client = $this->buildClient();
|
||||
|
||||
$client = $this->buildClient();
|
||||
$this->assertInstanceOf('\OpenStack\Transport\GuzzleClient', $client);
|
||||
|
||||
$this->assertInstanceOf('\OpenStack\Transport\GuzzleClient', $client);
|
||||
$response = $client->doRequest($url, $method);
|
||||
$this->assertInstanceOf('\GuzzleHttp\Message\Response', $response);
|
||||
|
||||
$response = $client->doRequest($url, $method);
|
||||
$this->assertInstanceOf('\GuzzleHttp\Message\Response', $response);
|
||||
}
|
||||
|
||||
}
|
||||
/**
|
||||
* @depends testDoRequest
|
||||
* @expectedException \OpenStack\Transport\FileNotFoundException
|
||||
*/
|
||||
public function testDoRequestException()
|
||||
{
|
||||
$url = 'http://www.openstack.org/this-does-no-exist';
|
||||
$method = 'GET';
|
||||
|
||||
/**
|
||||
* @depends testDoRequest
|
||||
* @expectedException \OpenStack\Transport\FileNotFoundException
|
||||
*/
|
||||
public function testDoRequestException() {
|
||||
$url = 'http://www.openstack.org/this-does-no-exist';
|
||||
$method = 'GET';
|
||||
$client = $this->buildClient();
|
||||
$client->doRequest($url, $method);
|
||||
}
|
||||
|
||||
$client = $this->buildClient();
|
||||
$client->doRequest($url, $method);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -2,17 +2,17 @@
|
||||
/* ============================================================================
|
||||
(c) Copyright 2012-2014 Hewlett-Packard Development Company, L.P.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
============================================================================ */
|
||||
/**
|
||||
* Unit tests for IdentityService.
|
||||
@ -24,414 +24,423 @@ require_once 'test/TestCase.php';
|
||||
use \OpenStack\Services\IdentityService;
|
||||
use \OpenStack\Bootstrap;
|
||||
|
||||
class IdentityServicesTest extends \OpenStack\Tests\TestCase
|
||||
{
|
||||
public function testConstructor()
|
||||
{
|
||||
$endpoint = self::conf('openstack.identity.url');
|
||||
$this->assertNotEmpty($endpoint);
|
||||
|
||||
class IdentityServiceTest extends \OpenStack\Tests\TestCase {
|
||||
$service = new IdentityService($endpoint, $this->getTransportClient());
|
||||
|
||||
public function testConstructor(){
|
||||
$endpoint = self::conf('openstack.identity.url');
|
||||
$this->assertNotEmpty($endpoint);
|
||||
$this->assertInstanceOf('\OpenStack\Services\IdentityService', $service);
|
||||
|
||||
$service = new IdentityService($endpoint, $this->getTransportClient());
|
||||
|
||||
$this->assertInstanceOf('\OpenStack\Services\IdentityService', $service);
|
||||
|
||||
return $service;
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testConstructor
|
||||
*/
|
||||
public function testUrl() {
|
||||
$endpoint = self::conf('openstack.identity.url');
|
||||
$service = new IdentityService($endpoint, $this->getTransportClient());
|
||||
|
||||
// If there is a trailing / we remove that from the endpoint. Our calls add
|
||||
// the / back where appropriate.
|
||||
$this->assertStringStartsWith(rtrim($endpoint, '/'), $service->url());
|
||||
|
||||
return $service;
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testUrl
|
||||
*/
|
||||
public function testAuthenticate($service){
|
||||
|
||||
// Canary: Make sure all the required params are declared.
|
||||
$settings = array(
|
||||
'openstack.identity.username',
|
||||
'openstack.identity.password',
|
||||
'openstack.identity.tenantId',
|
||||
);
|
||||
foreach ($settings as $setting) {
|
||||
$this->assertNotEmpty(self::conf($setting), "Required param: " . $setting);
|
||||
return $service;
|
||||
}
|
||||
|
||||
// Test username/password auth.
|
||||
$auth = array(
|
||||
'passwordCredentials' => array(
|
||||
'username' => self::conf('openstack.identity.username'),
|
||||
'password' => self::conf('openstack.identity.password'),
|
||||
),
|
||||
'tenantId' => self::conf('openstack.identity.tenantId'),
|
||||
);
|
||||
$tok = $service->authenticate($auth);
|
||||
$this->assertNotEmpty($tok);
|
||||
/**
|
||||
* @depends testConstructor
|
||||
*/
|
||||
public function testUrl()
|
||||
{
|
||||
$endpoint = self::conf('openstack.identity.url');
|
||||
$service = new IdentityService($endpoint, $this->getTransportClient());
|
||||
|
||||
// We should get the same token if we request again.
|
||||
$service = new IdentityService(self::conf('openstack.identity.url'), $this->getTransportClient());
|
||||
$tok2 = $service->authenticate($auth);
|
||||
$this->assertEquals($tok, $tok2);
|
||||
// If there is a trailing / we remove that from the endpoint. Our calls add
|
||||
// the / back where appropriate.
|
||||
$this->assertStringStartsWith(rtrim($endpoint, '/'), $service->url());
|
||||
|
||||
// Again with no tenant ID.
|
||||
$auth = array(
|
||||
'passwordCredentials' => array(
|
||||
'username' => self::conf('openstack.identity.username'),
|
||||
'password' => self::conf('openstack.identity.password'),
|
||||
),
|
||||
//'tenantId' => self::conf('openstack.identity.tenantId'),
|
||||
);
|
||||
$tok = $service->authenticate($auth);
|
||||
$this->assertNotEmpty($tok);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testAuthenticate
|
||||
*/
|
||||
public function testAuthenticateAsUser() {
|
||||
$service = new IdentityService(self::conf('openstack.identity.url'), $this->getTransportClient());
|
||||
|
||||
$user = self::conf('openstack.identity.username');
|
||||
$pass = self::conf('openstack.identity.password');
|
||||
$tenantId = self::conf('openstack.identity.tenantId');
|
||||
|
||||
$tok = $service->authenticateAsUser($user, $pass, $tenantId);
|
||||
|
||||
$this->assertNotEmpty($tok);
|
||||
|
||||
// Try again, this time with no tenant ID.
|
||||
$tok2 = $service->authenticateAsUser($user, $pass);
|
||||
$this->assertNotEmpty($tok2);
|
||||
|
||||
$details = $service->tokenDetails();
|
||||
$this->assertFalse(isset($details['tenant']));
|
||||
|
||||
return $service;
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testAuthenticateAsUser
|
||||
*/
|
||||
public function testToken($service) {
|
||||
$this->assertNotEmpty($service->token());
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testAuthenticateAsUser
|
||||
*/
|
||||
public function testIsExpired($service) {
|
||||
$this->assertFalse($service->isExpired());
|
||||
|
||||
$service2 = new IdentityService(self::conf('openstack.identity.url'), $this->getTransportClient());
|
||||
$this->assertTrue($service2->isExpired());
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testAuthenticateAsUser
|
||||
*/
|
||||
public function testTenantName() {
|
||||
$user = self::conf('openstack.identity.username');
|
||||
$pass = self::conf('openstack.identity.password');
|
||||
$tenantName = self::conf('openstack.identity.tenantName');
|
||||
|
||||
$service = new IdentityService(self::conf('openstack.identity.url'), $this->getTransportClient());
|
||||
$this->assertNull($service->tenantName());
|
||||
|
||||
$service->authenticateAsUser($user, $pass);
|
||||
$this->assertEmpty($service->tenantName());
|
||||
|
||||
$service = new IdentityService(self::conf('openstack.identity.url'), $this->getTransportClient());
|
||||
$ret = $service->authenticateAsUser($user, $pass, NULL, $tenantName);
|
||||
$this->assertNotEmpty($service->tenantName());
|
||||
|
||||
$service = new IdentityService(self::conf('openstack.identity.url'), $this->getTransportClient());
|
||||
$this->assertNull($service->tenantName());
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testAuthenticateAsUser
|
||||
*/
|
||||
public function testTenantId() {
|
||||
$user = self::conf('openstack.identity.username');
|
||||
$pass = self::conf('openstack.identity.password');
|
||||
$tenantId = self::conf('openstack.identity.tenantId');
|
||||
|
||||
$service = new IdentityService(self::conf('openstack.identity.url'), $this->getTransportClient());
|
||||
$this->assertNull($service->tenantId());
|
||||
|
||||
$service->authenticateAsUser($user, $pass);
|
||||
$this->assertEmpty($service->tenantId());
|
||||
|
||||
$service = new IdentityService(self::conf('openstack.identity.url'), $this->getTransportClient());
|
||||
$service->authenticateAsUser($user, $pass, $tenantId);
|
||||
$this->assertNotEmpty($service->tenantId());
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testAuthenticateAsUser
|
||||
*/
|
||||
public function testTokenDetails() {
|
||||
$now = time();
|
||||
$user = self::conf('openstack.identity.username');
|
||||
$pass = self::conf('openstack.identity.password');
|
||||
$tenantId = self::conf('openstack.identity.tenantId');
|
||||
|
||||
$service = new IdentityService(self::conf('openstack.identity.url'), $this->getTransportClient());
|
||||
$service->authenticateAsUser($user, $pass);
|
||||
|
||||
// Details for user auth.
|
||||
$details = $service->tokenDetails();
|
||||
$this->assertNotEmpty($details['id']);
|
||||
$this->assertFalse(isset($details['tenant']));
|
||||
|
||||
$ts = strtotime($details['expires']);
|
||||
$this->assertGreaterThan($now, $ts);
|
||||
|
||||
|
||||
// Test details for username auth.
|
||||
$service = new IdentityService(self::conf('openstack.identity.url'), $this->getTransportClient());
|
||||
$service->authenticateAsUser($user, $pass, $tenantId);
|
||||
|
||||
$details = $service->tokenDetails();
|
||||
|
||||
$expectUser = self::conf('openstack.identity.username');
|
||||
|
||||
$this->assertStringStartsWith($expectUser, $details['tenant']['name']);
|
||||
$this->assertNotEmpty($details['id']);
|
||||
$this->assertNotEmpty($details['tenant']['id']);
|
||||
|
||||
$this->assertEquals($tenantId, $details['tenant']['id']);
|
||||
|
||||
$ts = strtotime($details['expires']);
|
||||
$this->assertGreaterThan($now, $ts);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testAuthenticateAsUser
|
||||
*/
|
||||
public function testServiceCatalog($service) {
|
||||
$catalog = $service->serviceCatalog();
|
||||
|
||||
$this->assertGreaterThan(0, count($catalog));
|
||||
|
||||
$idService = NULL;
|
||||
foreach ($catalog as $item) {
|
||||
if ($item['type'] == 'identity') {
|
||||
$idService = $item;
|
||||
}
|
||||
return $service;
|
||||
}
|
||||
|
||||
$this->assertEquals('Identity', $idService['name']);
|
||||
$this->assertNotEmpty($idService['endpoints']);
|
||||
$this->assertNotEmpty($idService['endpoints'][0]['publicURL']);
|
||||
/**
|
||||
* @depends testUrl
|
||||
*/
|
||||
public function testAuthenticate($service)
|
||||
{
|
||||
// Canary: Make sure all the required params are declared.
|
||||
$settings = array(
|
||||
'openstack.identity.username',
|
||||
'openstack.identity.password',
|
||||
'openstack.identity.tenantId',
|
||||
);
|
||||
foreach ($settings as $setting) {
|
||||
$this->assertNotEmpty(self::conf($setting), "Required param: " . $setting);
|
||||
}
|
||||
|
||||
// Test filters.
|
||||
$justID = $service->serviceCatalog('identity');
|
||||
$this->assertEquals(1, count($justID));
|
||||
// Test username/password auth.
|
||||
$auth = array(
|
||||
'passwordCredentials' => array(
|
||||
'username' => self::conf('openstack.identity.username'),
|
||||
'password' => self::conf('openstack.identity.password'),
|
||||
),
|
||||
'tenantId' => self::conf('openstack.identity.tenantId'),
|
||||
);
|
||||
$tok = $service->authenticate($auth);
|
||||
$this->assertNotEmpty($tok);
|
||||
|
||||
$idService = $justID[0];
|
||||
$this->assertEquals('Identity', $idService['name']);
|
||||
$this->assertNotEmpty($idService['endpoints']);
|
||||
$this->assertNotEmpty($idService['endpoints'][0]['publicURL']);
|
||||
// We should get the same token if we request again.
|
||||
$service = new IdentityService(self::conf('openstack.identity.url'), $this->getTransportClient());
|
||||
$tok2 = $service->authenticate($auth);
|
||||
$this->assertEquals($tok, $tok2);
|
||||
|
||||
// Make sure a missed filter returns an empty set.
|
||||
$expectEmpty = $service->serviceCatalog('no-such-servicename');
|
||||
$this->assertEmpty($expectEmpty);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @depends testAuthenticateAsUser
|
||||
*/
|
||||
public function testUser($service) {
|
||||
$user = $service->user();
|
||||
|
||||
$this->assertEquals(self::conf('openstack.identity.username'), $user['name']);
|
||||
$this->assertNotEmpty($user['roles']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testAuthenticateAsUser
|
||||
* @group serialize
|
||||
*/
|
||||
public function testSerialization($service) {
|
||||
|
||||
$ser = serialize($service);
|
||||
|
||||
$this->assertNotEmpty($ser);
|
||||
|
||||
$again = unserialize($ser);
|
||||
|
||||
$this->assertInstanceOf('\OpenStack\Services\IdentityService', $again);
|
||||
|
||||
$this->assertEquals($service->tenantId(), $again->tenantId());
|
||||
$this->assertEquals($service->serviceCatalog(), $again->serviceCatalog());
|
||||
$this->assertEquals($service->tokenDetails(), $again->tokenDetails());
|
||||
$this->assertEquals($service->user(), $again->user());
|
||||
$this->assertFalse($again->isExpired());
|
||||
|
||||
$tenantId = $again->tenantId();
|
||||
|
||||
$newTok = $again->rescopeUsingTenantId($tenantId);
|
||||
|
||||
$this->assertNotEmpty($newTok);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group tenant
|
||||
*/
|
||||
public function testTenants() {
|
||||
$service = new IdentityService(self::conf('openstack.identity.url'), $this->getTransportClient());
|
||||
$service2 = new IdentityService(self::conf('openstack.identity.url'), $this->getTransportClient());
|
||||
$user = self::conf('openstack.identity.username');
|
||||
$pass = self::conf('openstack.identity.password');
|
||||
$tenantId = self::conf('openstack.identity.tenantId');
|
||||
$service->authenticateAsUser($user, $pass, $tenantId);
|
||||
|
||||
|
||||
$tenants = $service2->tenants($service->token());
|
||||
|
||||
$this->assertGreaterThan(0, count($tenants));
|
||||
$this->assertNotEmpty($tenants[0]['name']);
|
||||
$this->assertNotEmpty($tenants[0]['id']);
|
||||
|
||||
$tenants = $service->tenants();
|
||||
$this->assertGreaterThan(0, count($tenants));
|
||||
$this->assertNotEmpty($tenants[0]['name']);
|
||||
$this->assertNotEmpty($tenants[0]['id']);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @group tenant
|
||||
* @depends testTenants
|
||||
*/
|
||||
function testRescope() {
|
||||
$service = new IdentityService(self::conf('openstack.identity.url'), $this->getTransportClient());
|
||||
$user = self::conf('openstack.identity.username');
|
||||
$pass = self::conf('openstack.identity.password');
|
||||
$tenantId = self::conf('openstack.identity.tenantId');
|
||||
|
||||
// Authenticate without a tenant ID.
|
||||
$token = $service->authenticateAsUser($user, $pass);
|
||||
|
||||
$this->assertNotEmpty($token);
|
||||
|
||||
$details = $service->tokenDetails();
|
||||
$this->assertFalse(isset($details['tenant']));
|
||||
|
||||
$service->rescopeUsingTenantId($tenantId);
|
||||
|
||||
$details = $service->tokenDetails();
|
||||
$this->assertEquals($tenantId, $details['tenant']['id']);
|
||||
|
||||
// Test unscoping
|
||||
$service->rescopeUsingTenantId('');
|
||||
$details = $service->tokenDetails();
|
||||
$this->assertFalse(isset($details['tenant']));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group tenant
|
||||
* @depends testTenants
|
||||
*/
|
||||
function testRescopeByTenantName() {
|
||||
$service = new IdentityService(self::conf('openstack.identity.url'), $this->getTransportClient());
|
||||
$user = self::conf('openstack.identity.username');
|
||||
$pass = self::conf('openstack.identity.password');
|
||||
$tenantName = self::conf('openstack.identity.tenantName');
|
||||
|
||||
// Authenticate without a tenant ID.
|
||||
$token = $service->authenticateAsUser($user, $pass);
|
||||
|
||||
$this->assertNotEmpty($token);
|
||||
|
||||
$details = $service->tokenDetails();
|
||||
$this->assertFalse(isset($details['tenant']));
|
||||
|
||||
$service->rescopeUsingTenantName($tenantName);
|
||||
|
||||
$details = $service->tokenDetails();
|
||||
$this->assertEquals($tenantName, $details['tenant']['name']);
|
||||
|
||||
// Test unscoping
|
||||
$service->rescope('');
|
||||
$details = $service->tokenDetails();
|
||||
$this->assertFalse(isset($details['tenant']));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the bootstrap identity factory.
|
||||
* @depends testAuthenticateAsUser
|
||||
*/
|
||||
function testBootstrap() {
|
||||
|
||||
// We need to save the config settings and reset the bootstrap to this.
|
||||
// It does not remove the old settings. The means the identity fall through
|
||||
// for different settings may not happen because of ordering. So, we cache
|
||||
// and reset back to the default for each test.
|
||||
$reset = Bootstrap::$config;
|
||||
|
||||
// Test authenticating as a user.
|
||||
$settings = array(
|
||||
'username' => self::conf('openstack.identity.username'),
|
||||
'password' => self::conf('openstack.identity.password'),
|
||||
'endpoint' => self::conf('openstack.identity.url'),
|
||||
'tenantid' => self::conf('openstack.identity.tenantId'),
|
||||
'transport' => self::conf('transport'),
|
||||
'transport.debug' => self::conf('transport.debug', FALSE),
|
||||
'transport.ssl_verify' => self::conf('transport.ssl', TRUE),
|
||||
);
|
||||
if (self::conf('transport.timeout')) {
|
||||
$setting['transport.timeout'] = self::conf('transport.timeout');
|
||||
// Again with no tenant ID.
|
||||
$auth = array(
|
||||
'passwordCredentials' => array(
|
||||
'username' => self::conf('openstack.identity.username'),
|
||||
'password' => self::conf('openstack.identity.password'),
|
||||
),
|
||||
//'tenantId' => self::conf('openstack.identity.tenantId'),
|
||||
);
|
||||
$tok = $service->authenticate($auth);
|
||||
$this->assertNotEmpty($tok);
|
||||
}
|
||||
if (self::conf('transport.proxy')) {
|
||||
$setting['transport.proxy'] = self::conf('transport.proxy');
|
||||
|
||||
/**
|
||||
* @depends testAuthenticate
|
||||
*/
|
||||
public function testAuthenticateAsUser()
|
||||
{
|
||||
$service = new IdentityService(self::conf('openstack.identity.url'), $this->getTransportClient());
|
||||
|
||||
$user = self::conf('openstack.identity.username');
|
||||
$pass = self::conf('openstack.identity.password');
|
||||
$tenantId = self::conf('openstack.identity.tenantId');
|
||||
|
||||
$tok = $service->authenticateAsUser($user, $pass, $tenantId);
|
||||
|
||||
$this->assertNotEmpty($tok);
|
||||
|
||||
// Try again, this time with no tenant ID.
|
||||
$tok2 = $service->authenticateAsUser($user, $pass);
|
||||
$this->assertNotEmpty($tok2);
|
||||
|
||||
$details = $service->tokenDetails();
|
||||
$this->assertFalse(isset($details['tenant']));
|
||||
|
||||
return $service;
|
||||
}
|
||||
Bootstrap::setConfiguration($settings);
|
||||
|
||||
$is = Bootstrap::identity(TRUE);
|
||||
$this->assertInstanceOf('\OpenStack\Services\IdentityService', $is);
|
||||
|
||||
// Test getting a second instance from the cache.
|
||||
$is2 = Bootstrap::identity();
|
||||
$this->assertEquals($is, $is2);
|
||||
|
||||
// Test that forcing a refresh does so.
|
||||
$is2 = Bootstrap::identity(TRUE);
|
||||
$this->assertNotEquals($is, $is2);
|
||||
|
||||
Bootstrap::$config = $reset;
|
||||
|
||||
// Test with tenant name
|
||||
$settings = array(
|
||||
'username' => self::conf('openstack.identity.username'),
|
||||
'password' => self::conf('openstack.identity.password'),
|
||||
'endpoint' => self::conf('openstack.identity.url'),
|
||||
'tenantname' => self::conf('openstack.identity.tenantName'),
|
||||
'transport' => self::conf('transport'),
|
||||
'transport.debug' => self::conf('transport.debug', FALSE),
|
||||
'transport.ssl_verify' => self::conf('transport.ssl', TRUE),
|
||||
);
|
||||
if (self::conf('transport.timeout')) {
|
||||
$setting['transport.timeout'] = self::conf('transport.timeout');
|
||||
/**
|
||||
* @depends testAuthenticateAsUser
|
||||
*/
|
||||
public function testToken($service)
|
||||
{
|
||||
$this->assertNotEmpty($service->token());
|
||||
}
|
||||
if (self::conf('transport.proxy')) {
|
||||
$setting['transport.proxy'] = self::conf('transport.proxy');
|
||||
}
|
||||
Bootstrap::setConfiguration($settings);
|
||||
|
||||
$is = Bootstrap::identity(TRUE);
|
||||
$this->assertInstanceOf('\OpenStack\Services\IdentityService', $is);
|
||||
}
|
||||
/**
|
||||
* @depends testAuthenticateAsUser
|
||||
*/
|
||||
public function testIsExpired($service)
|
||||
{
|
||||
$this->assertFalse($service->isExpired());
|
||||
|
||||
$service2 = new IdentityService(self::conf('openstack.identity.url'), $this->getTransportClient());
|
||||
$this->assertTrue($service2->isExpired());
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testAuthenticateAsUser
|
||||
*/
|
||||
public function testTenantName()
|
||||
{
|
||||
$user = self::conf('openstack.identity.username');
|
||||
$pass = self::conf('openstack.identity.password');
|
||||
$tenantName = self::conf('openstack.identity.tenantName');
|
||||
|
||||
$service = new IdentityService(self::conf('openstack.identity.url'), $this->getTransportClient());
|
||||
$this->assertNull($service->tenantName());
|
||||
|
||||
$service->authenticateAsUser($user, $pass);
|
||||
$this->assertEmpty($service->tenantName());
|
||||
|
||||
$service = new IdentityService(self::conf('openstack.identity.url'), $this->getTransportClient());
|
||||
$ret = $service->authenticateAsUser($user, $pass, NULL, $tenantName);
|
||||
$this->assertNotEmpty($service->tenantName());
|
||||
|
||||
$service = new IdentityService(self::conf('openstack.identity.url'), $this->getTransportClient());
|
||||
$this->assertNull($service->tenantName());
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testAuthenticateAsUser
|
||||
*/
|
||||
public function testTenantId()
|
||||
{
|
||||
$user = self::conf('openstack.identity.username');
|
||||
$pass = self::conf('openstack.identity.password');
|
||||
$tenantId = self::conf('openstack.identity.tenantId');
|
||||
|
||||
$service = new IdentityService(self::conf('openstack.identity.url'), $this->getTransportClient());
|
||||
$this->assertNull($service->tenantId());
|
||||
|
||||
$service->authenticateAsUser($user, $pass);
|
||||
$this->assertEmpty($service->tenantId());
|
||||
|
||||
$service = new IdentityService(self::conf('openstack.identity.url'), $this->getTransportClient());
|
||||
$service->authenticateAsUser($user, $pass, $tenantId);
|
||||
$this->assertNotEmpty($service->tenantId());
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testAuthenticateAsUser
|
||||
*/
|
||||
public function testTokenDetails()
|
||||
{
|
||||
$now = time();
|
||||
$user = self::conf('openstack.identity.username');
|
||||
$pass = self::conf('openstack.identity.password');
|
||||
$tenantId = self::conf('openstack.identity.tenantId');
|
||||
|
||||
$service = new IdentityService(self::conf('openstack.identity.url'), $this->getTransportClient());
|
||||
$service->authenticateAsUser($user, $pass);
|
||||
|
||||
// Details for user auth.
|
||||
$details = $service->tokenDetails();
|
||||
$this->assertNotEmpty($details['id']);
|
||||
$this->assertFalse(isset($details['tenant']));
|
||||
|
||||
$ts = strtotime($details['expires']);
|
||||
$this->assertGreaterThan($now, $ts);
|
||||
|
||||
// Test details for username auth.
|
||||
$service = new IdentityService(self::conf('openstack.identity.url'), $this->getTransportClient());
|
||||
$service->authenticateAsUser($user, $pass, $tenantId);
|
||||
|
||||
$details = $service->tokenDetails();
|
||||
|
||||
$expectUser = self::conf('openstack.identity.username');
|
||||
|
||||
$this->assertStringStartsWith($expectUser, $details['tenant']['name']);
|
||||
$this->assertNotEmpty($details['id']);
|
||||
$this->assertNotEmpty($details['tenant']['id']);
|
||||
|
||||
$this->assertEquals($tenantId, $details['tenant']['id']);
|
||||
|
||||
$ts = strtotime($details['expires']);
|
||||
$this->assertGreaterThan($now, $ts);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testAuthenticateAsUser
|
||||
*/
|
||||
public function testServiceCatalog($service)
|
||||
{
|
||||
$catalog = $service->serviceCatalog();
|
||||
|
||||
$this->assertGreaterThan(0, count($catalog));
|
||||
|
||||
$idService = NULL;
|
||||
foreach ($catalog as $item) {
|
||||
if ($item['type'] == 'identity') {
|
||||
$idService = $item;
|
||||
}
|
||||
}
|
||||
|
||||
$this->assertEquals('Identity', $idService['name']);
|
||||
$this->assertNotEmpty($idService['endpoints']);
|
||||
$this->assertNotEmpty($idService['endpoints'][0]['publicURL']);
|
||||
|
||||
// Test filters.
|
||||
$justID = $service->serviceCatalog('identity');
|
||||
$this->assertEquals(1, count($justID));
|
||||
|
||||
$idService = $justID[0];
|
||||
$this->assertEquals('Identity', $idService['name']);
|
||||
$this->assertNotEmpty($idService['endpoints']);
|
||||
$this->assertNotEmpty($idService['endpoints'][0]['publicURL']);
|
||||
|
||||
// Make sure a missed filter returns an empty set.
|
||||
$expectEmpty = $service->serviceCatalog('no-such-servicename');
|
||||
$this->assertEmpty($expectEmpty);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testAuthenticateAsUser
|
||||
*/
|
||||
public function testUser($service)
|
||||
{
|
||||
$user = $service->user();
|
||||
|
||||
$this->assertEquals(self::conf('openstack.identity.username'), $user['name']);
|
||||
$this->assertNotEmpty($user['roles']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testAuthenticateAsUser
|
||||
* @group serialize
|
||||
*/
|
||||
public function testSerialization($service)
|
||||
{
|
||||
$ser = serialize($service);
|
||||
|
||||
$this->assertNotEmpty($ser);
|
||||
|
||||
$again = unserialize($ser);
|
||||
|
||||
$this->assertInstanceOf('\OpenStack\Services\IdentityService', $again);
|
||||
|
||||
$this->assertEquals($service->tenantId(), $again->tenantId());
|
||||
$this->assertEquals($service->serviceCatalog(), $again->serviceCatalog());
|
||||
$this->assertEquals($service->tokenDetails(), $again->tokenDetails());
|
||||
$this->assertEquals($service->user(), $again->user());
|
||||
$this->assertFalse($again->isExpired());
|
||||
|
||||
$tenantId = $again->tenantId();
|
||||
|
||||
$newTok = $again->rescopeUsingTenantId($tenantId);
|
||||
|
||||
$this->assertNotEmpty($newTok);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group tenant
|
||||
*/
|
||||
public function testTenants()
|
||||
{
|
||||
$service = new IdentityService(self::conf('openstack.identity.url'), $this->getTransportClient());
|
||||
$service2 = new IdentityService(self::conf('openstack.identity.url'), $this->getTransportClient());
|
||||
$user = self::conf('openstack.identity.username');
|
||||
$pass = self::conf('openstack.identity.password');
|
||||
$tenantId = self::conf('openstack.identity.tenantId');
|
||||
$service->authenticateAsUser($user, $pass, $tenantId);
|
||||
|
||||
$tenants = $service2->tenants($service->token());
|
||||
|
||||
$this->assertGreaterThan(0, count($tenants));
|
||||
$this->assertNotEmpty($tenants[0]['name']);
|
||||
$this->assertNotEmpty($tenants[0]['id']);
|
||||
|
||||
$tenants = $service->tenants();
|
||||
$this->assertGreaterThan(0, count($tenants));
|
||||
$this->assertNotEmpty($tenants[0]['name']);
|
||||
$this->assertNotEmpty($tenants[0]['id']);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @group tenant
|
||||
* @depends testTenants
|
||||
*/
|
||||
public function testRescope()
|
||||
{
|
||||
$service = new IdentityService(self::conf('openstack.identity.url'), $this->getTransportClient());
|
||||
$user = self::conf('openstack.identity.username');
|
||||
$pass = self::conf('openstack.identity.password');
|
||||
$tenantId = self::conf('openstack.identity.tenantId');
|
||||
|
||||
// Authenticate without a tenant ID.
|
||||
$token = $service->authenticateAsUser($user, $pass);
|
||||
|
||||
$this->assertNotEmpty($token);
|
||||
|
||||
$details = $service->tokenDetails();
|
||||
$this->assertFalse(isset($details['tenant']));
|
||||
|
||||
$service->rescopeUsingTenantId($tenantId);
|
||||
|
||||
$details = $service->tokenDetails();
|
||||
$this->assertEquals($tenantId, $details['tenant']['id']);
|
||||
|
||||
// Test unscoping
|
||||
$service->rescopeUsingTenantId('');
|
||||
$details = $service->tokenDetails();
|
||||
$this->assertFalse(isset($details['tenant']));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group tenant
|
||||
* @depends testTenants
|
||||
*/
|
||||
public function testRescopeByTenantName()
|
||||
{
|
||||
$service = new IdentityService(self::conf('openstack.identity.url'), $this->getTransportClient());
|
||||
$user = self::conf('openstack.identity.username');
|
||||
$pass = self::conf('openstack.identity.password');
|
||||
$tenantName = self::conf('openstack.identity.tenantName');
|
||||
|
||||
// Authenticate without a tenant ID.
|
||||
$token = $service->authenticateAsUser($user, $pass);
|
||||
|
||||
$this->assertNotEmpty($token);
|
||||
|
||||
$details = $service->tokenDetails();
|
||||
$this->assertFalse(isset($details['tenant']));
|
||||
|
||||
$service->rescopeUsingTenantName($tenantName);
|
||||
|
||||
$details = $service->tokenDetails();
|
||||
$this->assertEquals($tenantName, $details['tenant']['name']);
|
||||
|
||||
// Test unscoping
|
||||
$service->rescope('');
|
||||
$details = $service->tokenDetails();
|
||||
$this->assertFalse(isset($details['tenant']));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the bootstrap identity factory.
|
||||
* @depends testAuthenticateAsUser
|
||||
*/
|
||||
public function testBootstrap()
|
||||
{
|
||||
// We need to save the config settings and reset the bootstrap to this.
|
||||
// It does not remove the old settings. The means the identity fall through
|
||||
// for different settings may not happen because of ordering. So, we cache
|
||||
// and reset back to the default for each test.
|
||||
$reset = Bootstrap::$config;
|
||||
|
||||
// Test authenticating as a user.
|
||||
$settings = array(
|
||||
'username' => self::conf('openstack.identity.username'),
|
||||
'password' => self::conf('openstack.identity.password'),
|
||||
'endpoint' => self::conf('openstack.identity.url'),
|
||||
'tenantid' => self::conf('openstack.identity.tenantId'),
|
||||
'transport' => self::conf('transport'),
|
||||
'transport.debug' => self::conf('transport.debug', FALSE),
|
||||
'transport.ssl_verify' => self::conf('transport.ssl', TRUE),
|
||||
);
|
||||
if (self::conf('transport.timeout')) {
|
||||
$setting['transport.timeout'] = self::conf('transport.timeout');
|
||||
}
|
||||
if (self::conf('transport.proxy')) {
|
||||
$setting['transport.proxy'] = self::conf('transport.proxy');
|
||||
}
|
||||
Bootstrap::setConfiguration($settings);
|
||||
|
||||
$is = Bootstrap::identity(TRUE);
|
||||
$this->assertInstanceOf('\OpenStack\Services\IdentityService', $is);
|
||||
|
||||
// Test getting a second instance from the cache.
|
||||
$is2 = Bootstrap::identity();
|
||||
$this->assertEquals($is, $is2);
|
||||
|
||||
// Test that forcing a refresh does so.
|
||||
$is2 = Bootstrap::identity(TRUE);
|
||||
$this->assertNotEquals($is, $is2);
|
||||
|
||||
Bootstrap::$config = $reset;
|
||||
|
||||
// Test with tenant name
|
||||
$settings = array(
|
||||
'username' => self::conf('openstack.identity.username'),
|
||||
'password' => self::conf('openstack.identity.password'),
|
||||
'endpoint' => self::conf('openstack.identity.url'),
|
||||
'tenantname' => self::conf('openstack.identity.tenantName'),
|
||||
'transport' => self::conf('transport'),
|
||||
'transport.debug' => self::conf('transport.debug', FALSE),
|
||||
'transport.ssl_verify' => self::conf('transport.ssl', TRUE),
|
||||
);
|
||||
if (self::conf('transport.timeout')) {
|
||||
$setting['transport.timeout'] = self::conf('transport.timeout');
|
||||
}
|
||||
if (self::conf('transport.proxy')) {
|
||||
$setting['transport.proxy'] = self::conf('transport.proxy');
|
||||
}
|
||||
Bootstrap::setConfiguration($settings);
|
||||
|
||||
$is = Bootstrap::identity(TRUE);
|
||||
$this->assertInstanceOf('\OpenStack\Services\IdentityService', $is);
|
||||
}
|
||||
}
|
||||
|
@ -2,17 +2,17 @@
|
||||
/* ============================================================================
|
||||
(c) Copyright 2012-2014 Hewlett-Packard Development Company, L.P.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
============================================================================ */
|
||||
/**
|
||||
* Unit tests for ObjectStorage.
|
||||
@ -24,281 +24,292 @@ require_once 'test/TestCase.php';
|
||||
use \OpenStack\Storage\ObjectStorage\Object;
|
||||
use \OpenStack\Storage\ObjectStorage\ACL;
|
||||
|
||||
|
||||
class ObjectStorageTest extends \OpenStack\Tests\TestCase {
|
||||
|
||||
/**
|
||||
* Canary test.
|
||||
*/
|
||||
public function testSettings() {
|
||||
$this->assertTrue(!empty(self::$settings));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Swift-based authentication.
|
||||
* @group deprecated
|
||||
*/
|
||||
public function testSwiftAuthentication() {
|
||||
|
||||
$ostore = $this->swiftAuth();
|
||||
|
||||
$this->assertInstanceOf('\OpenStack\Storage\ObjectStorage', $ostore);
|
||||
$this->assertTrue(strlen($ostore->token()) > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group auth
|
||||
*/
|
||||
public function testConstructor() {
|
||||
$ident = $this->identity();
|
||||
|
||||
$services = $ident->serviceCatalog(\OpenStack\Storage\ObjectStorage::SERVICE_TYPE);
|
||||
|
||||
if (empty($services)) {
|
||||
throw new \Exception('No object-store service found.');
|
||||
}
|
||||
|
||||
//$serviceURL = $services[0]['endpoints'][0]['adminURL'];
|
||||
$serviceURL = $services[0]['endpoints'][0]['publicURL'];
|
||||
|
||||
$ostore = new \OpenStack\Storage\ObjectStorage($ident->token(), $serviceURL, $this->getTransportClient());
|
||||
|
||||
$this->assertInstanceOf('\OpenStack\Storage\ObjectStorage', $ostore);
|
||||
$this->assertTrue(strlen($ostore->token()) > 0);
|
||||
|
||||
}
|
||||
|
||||
public function testNewFromServiceCatalog() {
|
||||
$ident = $this->identity();
|
||||
$tok = $ident->token();
|
||||
$cat = $ident->serviceCatalog();
|
||||
$ostore = \OpenStack\Storage\ObjectStorage::newFromServiceCatalog($cat, $tok, self::$settings['openstack.swift.region'], $this->getTransportClient());
|
||||
$this->assertInstanceOf('\OpenStack\Storage\ObjectStorage', $ostore);
|
||||
$this->assertTrue(strlen($ostore->token()) > 0);
|
||||
}
|
||||
|
||||
public function testFailedNewFromServiceCatalog(){
|
||||
$ident = $this->identity();
|
||||
$tok = $ident->token();
|
||||
$cat = $ident->serviceCatalog();
|
||||
$ostore = \OpenStack\Storage\ObjectStorage::newFromServiceCatalog($cat, $tok, 'region-w.geo-99999.fake', $this->getTransportClient());
|
||||
$this->assertEmpty($ostore);
|
||||
}
|
||||
|
||||
public function testNewFromIdnetity() {
|
||||
$ident = $this->identity();
|
||||
$ostore = \OpenStack\Storage\ObjectStorage::newFromIdentity($ident, self::$settings['openstack.swift.region'], $this->getTransportClient());
|
||||
$this->assertInstanceOf('\OpenStack\Storage\ObjectStorage', $ostore);
|
||||
$this->assertTrue(strlen($ostore->token()) > 0);
|
||||
}
|
||||
|
||||
public function testNewFromIdentityAltRegion() {
|
||||
$ident = $this->identity();
|
||||
$ostore = \OpenStack\Storage\ObjectStorage::newFromIdentity($ident, 'region-b.geo-1', $this->getTransportClient());
|
||||
$this->assertInstanceOf('\OpenStack\Storage\ObjectStorage', $ostore);
|
||||
$this->assertTrue(strlen($ostore->token()) > 0);
|
||||
|
||||
// Make sure the store is not the same as the default region.
|
||||
$ostoreDefault = \OpenStack\Storage\ObjectStorage::newFromIdentity($ident, self::$settings['openstack.swift.region'], $this->getTransportClient());
|
||||
$this->assertNotEquals($ostore, $ostoreDefault);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group auth
|
||||
* @ group acl
|
||||
*/
|
||||
public function testCreateContainer() {
|
||||
$testCollection = self::$settings['openstack.swift.container'];
|
||||
|
||||
$this->assertNotEmpty($testCollection, "Canary: container name must be in settings file.");
|
||||
|
||||
$store = $this->objectStore();//swiftAuth();
|
||||
|
||||
$this->destroyContainerFixture();
|
||||
/*
|
||||
if ($store->hasContainer($testCollection)) {
|
||||
$store->deleteContainer($testCollection);
|
||||
}
|
||||
class ObjectStorageTest extends \OpenStack\Tests\TestCase
|
||||
{
|
||||
/**
|
||||
* Canary test.
|
||||
*/
|
||||
|
||||
$md = array('Foo' => 1234);
|
||||
|
||||
$ret = $store->createContainer($testCollection, NULL, $md);
|
||||
$this->assertTrue($ret, "Create container");
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @group auth
|
||||
* @depends testCreateContainer
|
||||
*/
|
||||
public function testAccountInfo () {
|
||||
$store = $this->objectStore();
|
||||
|
||||
$info = $store->accountInfo();
|
||||
|
||||
$this->assertGreaterThan(0, $info['containers']);
|
||||
$this->assertGreaterThanOrEqual(0, $info['bytes']);
|
||||
$this->assertGreaterThanOrEqual(0, $info['objects']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testCreateContainer
|
||||
*/
|
||||
public function testContainers() {
|
||||
$store = $this->objectStore();
|
||||
$containers = $store->containers();
|
||||
|
||||
$this->assertNotEmpty($containers);
|
||||
|
||||
//$first = array_shift($containers);
|
||||
|
||||
$testCollection = self::conf('openstack.swift.container');
|
||||
$testContainer = $containers[$testCollection];
|
||||
$this->assertEquals($testCollection, $testContainer->name());
|
||||
$this->assertEquals(0, $testContainer->bytes());
|
||||
$this->assertEquals(0, $testContainer->count());
|
||||
|
||||
// Make sure we get back an ACL:
|
||||
$this->assertInstanceOf('\OpenStack\Storage\ObjectStorage\ACL', $testContainer->acl());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testCreateContainer
|
||||
*/
|
||||
public function testContainer() {
|
||||
$testCollection = self::$settings['openstack.swift.container'];
|
||||
$store = $this->objectStore();
|
||||
|
||||
$container = $store->container($testCollection);
|
||||
|
||||
$this->assertEquals(0, $container->bytes());
|
||||
$this->assertEquals(0, $container->count());
|
||||
$this->assertEquals($testCollection, $container->name());
|
||||
|
||||
$md = $container->metadata();
|
||||
$this->assertEquals(1, count($md));
|
||||
$this->assertEquals('1234', $md['Foo']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testCreateContainer
|
||||
*/
|
||||
public function testHasContainer() {
|
||||
$testCollection = self::$settings['openstack.swift.container'];
|
||||
$store = $this->objectStore();
|
||||
|
||||
$this->assertTrue($store->hasContainer($testCollection));
|
||||
$this->assertFalse($store->hasContainer('nihil'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testHasContainer
|
||||
*/
|
||||
public function testDeleteContainer() {
|
||||
$testCollection = self::$settings['openstack.swift.container'];
|
||||
|
||||
$store = $this->objectStore();
|
||||
//$ret = $store->createContainer($testCollection);
|
||||
//$this->assertTrue($store->hasContainer($testCollection));
|
||||
|
||||
$ret = $store->deleteContainer($testCollection);
|
||||
|
||||
$this->assertTrue($ret);
|
||||
|
||||
// Now we try to delete a container that does not exist.
|
||||
$ret = $store->deleteContainer('nihil');
|
||||
$this->assertFalse($ret);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \OpenStack\Storage\ObjectStorage\ContainerNotEmptyException
|
||||
*/
|
||||
public function testDeleteNonEmptyContainer() {
|
||||
|
||||
$testCollection = self::$settings['openstack.swift.container'];
|
||||
|
||||
$this->assertNotEmpty($testCollection);
|
||||
|
||||
$store = $this->objectStore();
|
||||
$store->createContainer($testCollection);
|
||||
|
||||
$container = $store->container($testCollection);
|
||||
$container->save(new Object('test', 'test', 'text/plain'));
|
||||
|
||||
try {
|
||||
$ret = $store->deleteContainer($testCollection);
|
||||
}
|
||||
catch (\Exception $e) {
|
||||
$container->delete('test');
|
||||
$store->deleteContainer($testCollection);
|
||||
throw $e;
|
||||
public function testSettings()
|
||||
{
|
||||
$this->assertTrue(!empty(self::$settings));
|
||||
}
|
||||
|
||||
try {
|
||||
$container->delete('test');
|
||||
}
|
||||
// Skip 404s.
|
||||
catch (\Exception $e) {}
|
||||
/**
|
||||
* Test Swift-based authentication.
|
||||
* @group deprecated
|
||||
*/
|
||||
public function testSwiftAuthentication()
|
||||
{
|
||||
$ostore = $this->swiftAuth();
|
||||
|
||||
$store->deleteContainer($testCollection);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testCreateContainer
|
||||
* @group acl
|
||||
*/
|
||||
public function testCreateContainerPublic() {
|
||||
$testCollection = self::$settings['openstack.swift.container'] . 'PUBLIC';
|
||||
$store = $this->objectStore();
|
||||
if ($store->hasContainer($testCollection)) {
|
||||
$store->deleteContainer($testCollection);
|
||||
$this->assertInstanceOf('\OpenStack\Storage\ObjectStorage', $ostore);
|
||||
$this->assertTrue(strlen($ostore->token()) > 0);
|
||||
}
|
||||
|
||||
$ret = $store->createContainer($testCollection, ACL::makePublic());
|
||||
$container = $store->container($testCollection);
|
||||
/**
|
||||
* @group auth
|
||||
*/
|
||||
public function testConstructor()
|
||||
{
|
||||
$ident = $this->identity();
|
||||
|
||||
// Now test that we can get the container contents. Since there is
|
||||
// no content in the container, we use the format=xml to make sure
|
||||
// we get some data back.
|
||||
$url = $container->url() . '?format=xml';
|
||||
$services = $ident->serviceCatalog(\OpenStack\Storage\ObjectStorage::SERVICE_TYPE);
|
||||
|
||||
// Use CURL to get better debugging:
|
||||
//$client = \OpenStack\Transport::instance();
|
||||
//$response = $client->doRequest($url, 'GET');
|
||||
if (empty($services)) {
|
||||
throw new \Exception('No object-store service found.');
|
||||
}
|
||||
|
||||
$data = file_get_contents($url);
|
||||
$this->assertNotEmpty($data, $url);
|
||||
//$serviceURL = $services[0]['endpoints'][0]['adminURL'];
|
||||
$serviceURL = $services[0]['endpoints'][0]['publicURL'];
|
||||
|
||||
$containers = $store->containers();
|
||||
//throw new \Exception(print_r($containers, TRUE));
|
||||
$ostore = new \OpenStack\Storage\ObjectStorage($ident->token(), $serviceURL, $this->getTransportClient());
|
||||
|
||||
$store->deleteContainer($testCollection);
|
||||
}
|
||||
$this->assertInstanceOf('\OpenStack\Storage\ObjectStorage', $ostore);
|
||||
$this->assertTrue(strlen($ostore->token()) > 0);
|
||||
|
||||
/**
|
||||
* @depends testCreateContainerPublic
|
||||
*/
|
||||
public function testChangeContainerACL() {
|
||||
$testCollection = self::$settings['openstack.swift.container'] . 'PUBLIC';
|
||||
$store = $this->objectStore();
|
||||
if ($store->hasContainer($testCollection)) {
|
||||
$store->deleteContainer($testCollection);
|
||||
}
|
||||
$ret = $store->createContainer($testCollection);
|
||||
|
||||
public function testNewFromServiceCatalog()
|
||||
{
|
||||
$ident = $this->identity();
|
||||
$tok = $ident->token();
|
||||
$cat = $ident->serviceCatalog();
|
||||
$ostore = \OpenStack\Storage\ObjectStorage::newFromServiceCatalog($cat, $tok, self::$settings['openstack.swift.region'], $this->getTransportClient());
|
||||
$this->assertInstanceOf('\OpenStack\Storage\ObjectStorage', $ostore);
|
||||
$this->assertTrue(strlen($ostore->token()) > 0);
|
||||
}
|
||||
|
||||
$acl = \OpenStack\Storage\ObjectStorage\ACL::makePublic();
|
||||
$ret = $store->changeContainerACL($testCollection, $acl);
|
||||
public function testFailedNewFromServiceCatalog()
|
||||
{
|
||||
$ident = $this->identity();
|
||||
$tok = $ident->token();
|
||||
$cat = $ident->serviceCatalog();
|
||||
$ostore = \OpenStack\Storage\ObjectStorage::newFromServiceCatalog($cat, $tok, 'region-w.geo-99999.fake', $this->getTransportClient());
|
||||
$this->assertEmpty($ostore);
|
||||
}
|
||||
|
||||
$this->assertFalse($ret);
|
||||
public function testNewFromIdnetity()
|
||||
{
|
||||
$ident = $this->identity();
|
||||
$ostore = \OpenStack\Storage\ObjectStorage::newFromIdentity($ident, self::$settings['openstack.swift.region'], $this->getTransportClient());
|
||||
$this->assertInstanceOf('\OpenStack\Storage\ObjectStorage', $ostore);
|
||||
$this->assertTrue(strlen($ostore->token()) > 0);
|
||||
}
|
||||
|
||||
$container = $store->container($testCollection);
|
||||
$url = $container->url() . '?format=xml';
|
||||
$data = file_get_contents($url);
|
||||
$this->assertNotEmpty($data, $url);
|
||||
public function testNewFromIdentityAltRegion()
|
||||
{
|
||||
$ident = $this->identity();
|
||||
$ostore = \OpenStack\Storage\ObjectStorage::newFromIdentity($ident, 'region-b.geo-1', $this->getTransportClient());
|
||||
$this->assertInstanceOf('\OpenStack\Storage\ObjectStorage', $ostore);
|
||||
$this->assertTrue(strlen($ostore->token()) > 0);
|
||||
|
||||
$store->deleteContainer($testCollection);
|
||||
}
|
||||
// Make sure the store is not the same as the default region.
|
||||
$ostoreDefault = \OpenStack\Storage\ObjectStorage::newFromIdentity($ident, self::$settings['openstack.swift.region'], $this->getTransportClient());
|
||||
$this->assertNotEquals($ostore, $ostoreDefault);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group auth
|
||||
* @ group acl
|
||||
*/
|
||||
public function testCreateContainer()
|
||||
{
|
||||
$testCollection = self::$settings['openstack.swift.container'];
|
||||
|
||||
$this->assertNotEmpty($testCollection, "Canary: container name must be in settings file.");
|
||||
|
||||
$store = $this->objectStore();//swiftAuth();
|
||||
|
||||
$this->destroyContainerFixture();
|
||||
/*
|
||||
if ($store->hasContainer($testCollection)) {
|
||||
$store->deleteContainer($testCollection);
|
||||
}
|
||||
*/
|
||||
|
||||
$md = array('Foo' => 1234);
|
||||
|
||||
$ret = $store->createContainer($testCollection, NULL, $md);
|
||||
$this->assertTrue($ret, "Create container");
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @group auth
|
||||
* @depends testCreateContainer
|
||||
*/
|
||||
public function testAccountInfo()
|
||||
{
|
||||
$store = $this->objectStore();
|
||||
|
||||
$info = $store->accountInfo();
|
||||
|
||||
$this->assertGreaterThan(0, $info['containers']);
|
||||
$this->assertGreaterThanOrEqual(0, $info['bytes']);
|
||||
$this->assertGreaterThanOrEqual(0, $info['objects']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testCreateContainer
|
||||
*/
|
||||
public function testContainers()
|
||||
{
|
||||
$store = $this->objectStore();
|
||||
$containers = $store->containers();
|
||||
|
||||
$this->assertNotEmpty($containers);
|
||||
|
||||
//$first = array_shift($containers);
|
||||
|
||||
$testCollection = self::conf('openstack.swift.container');
|
||||
$testContainer = $containers[$testCollection];
|
||||
$this->assertEquals($testCollection, $testContainer->name());
|
||||
$this->assertEquals(0, $testContainer->bytes());
|
||||
$this->assertEquals(0, $testContainer->count());
|
||||
|
||||
// Make sure we get back an ACL:
|
||||
$this->assertInstanceOf('\OpenStack\Storage\ObjectStorage\ACL', $testContainer->acl());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testCreateContainer
|
||||
*/
|
||||
public function testContainer()
|
||||
{
|
||||
$testCollection = self::$settings['openstack.swift.container'];
|
||||
$store = $this->objectStore();
|
||||
|
||||
$container = $store->container($testCollection);
|
||||
|
||||
$this->assertEquals(0, $container->bytes());
|
||||
$this->assertEquals(0, $container->count());
|
||||
$this->assertEquals($testCollection, $container->name());
|
||||
|
||||
$md = $container->metadata();
|
||||
$this->assertEquals(1, count($md));
|
||||
$this->assertEquals('1234', $md['Foo']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testCreateContainer
|
||||
*/
|
||||
public function testHasContainer()
|
||||
{
|
||||
$testCollection = self::$settings['openstack.swift.container'];
|
||||
$store = $this->objectStore();
|
||||
|
||||
$this->assertTrue($store->hasContainer($testCollection));
|
||||
$this->assertFalse($store->hasContainer('nihil'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testHasContainer
|
||||
*/
|
||||
public function testDeleteContainer()
|
||||
{
|
||||
$testCollection = self::$settings['openstack.swift.container'];
|
||||
|
||||
$store = $this->objectStore();
|
||||
//$ret = $store->createContainer($testCollection);
|
||||
//$this->assertTrue($store->hasContainer($testCollection));
|
||||
|
||||
$ret = $store->deleteContainer($testCollection);
|
||||
|
||||
$this->assertTrue($ret);
|
||||
|
||||
// Now we try to delete a container that does not exist.
|
||||
$ret = $store->deleteContainer('nihil');
|
||||
$this->assertFalse($ret);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \OpenStack\Storage\ObjectStorage\ContainerNotEmptyException
|
||||
*/
|
||||
public function testDeleteNonEmptyContainer()
|
||||
{
|
||||
$testCollection = self::$settings['openstack.swift.container'];
|
||||
|
||||
$this->assertNotEmpty($testCollection);
|
||||
|
||||
$store = $this->objectStore();
|
||||
$store->createContainer($testCollection);
|
||||
|
||||
$container = $store->container($testCollection);
|
||||
$container->save(new Object('test', 'test', 'text/plain'));
|
||||
|
||||
try {
|
||||
$ret = $store->deleteContainer($testCollection);
|
||||
} catch (\Exception $e) {
|
||||
$container->delete('test');
|
||||
$store->deleteContainer($testCollection);
|
||||
throw $e;
|
||||
}
|
||||
|
||||
try {
|
||||
$container->delete('test');
|
||||
}
|
||||
// Skip 404s.
|
||||
catch (\Exception $e) {}
|
||||
|
||||
$store->deleteContainer($testCollection);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testCreateContainer
|
||||
* @group acl
|
||||
*/
|
||||
public function testCreateContainerPublic()
|
||||
{
|
||||
$testCollection = self::$settings['openstack.swift.container'] . 'PUBLIC';
|
||||
$store = $this->objectStore();
|
||||
if ($store->hasContainer($testCollection)) {
|
||||
$store->deleteContainer($testCollection);
|
||||
}
|
||||
|
||||
$ret = $store->createContainer($testCollection, ACL::makePublic());
|
||||
$container = $store->container($testCollection);
|
||||
|
||||
// Now test that we can get the container contents. Since there is
|
||||
// no content in the container, we use the format=xml to make sure
|
||||
// we get some data back.
|
||||
$url = $container->url() . '?format=xml';
|
||||
|
||||
// Use CURL to get better debugging:
|
||||
//$client = \OpenStack\Transport::instance();
|
||||
//$response = $client->doRequest($url, 'GET');
|
||||
|
||||
$data = file_get_contents($url);
|
||||
$this->assertNotEmpty($data, $url);
|
||||
|
||||
$containers = $store->containers();
|
||||
//throw new \Exception(print_r($containers, TRUE));
|
||||
|
||||
$store->deleteContainer($testCollection);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testCreateContainerPublic
|
||||
*/
|
||||
public function testChangeContainerACL()
|
||||
{
|
||||
$testCollection = self::$settings['openstack.swift.container'] . 'PUBLIC';
|
||||
$store = $this->objectStore();
|
||||
if ($store->hasContainer($testCollection)) {
|
||||
$store->deleteContainer($testCollection);
|
||||
}
|
||||
$ret = $store->createContainer($testCollection);
|
||||
|
||||
$acl = \OpenStack\Storage\ObjectStorage\ACL::makePublic();
|
||||
$ret = $store->changeContainerACL($testCollection, $acl);
|
||||
|
||||
$this->assertFalse($ret);
|
||||
|
||||
$container = $store->container($testCollection);
|
||||
$url = $container->url() . '?format=xml';
|
||||
$data = file_get_contents($url);
|
||||
$this->assertNotEmpty($data, $url);
|
||||
|
||||
$store->deleteContainer($testCollection);
|
||||
}
|
||||
}
|
||||
|
@ -2,17 +2,17 @@
|
||||
/* ============================================================================
|
||||
(c) Copyright 2012-2014 Hewlett-Packard Development Company, L.P.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
============================================================================ */
|
||||
/**
|
||||
* Unit tests for ObjectStorage Object.
|
||||
@ -23,123 +23,130 @@ require_once 'test/TestCase.php';
|
||||
|
||||
use \OpenStack\Storage\ObjectStorage\Object;
|
||||
|
||||
class ObjectTest extends \OpenStack\Tests\TestCase {
|
||||
class ObjectTest extends \OpenStack\Tests\TestCase
|
||||
{
|
||||
const FNAME = 'descartes.txt';
|
||||
const FCONTENT = 'Cogito ergo sum.';
|
||||
const FTYPE = 'text/plain; charset=ISO-8859-1';
|
||||
|
||||
const FNAME = 'descartes.txt';
|
||||
const FCONTENT = 'Cogito ergo sum.';
|
||||
const FTYPE = 'text/plain; charset=ISO-8859-1';
|
||||
/**
|
||||
* Set up a basic object fixture.
|
||||
*
|
||||
* This provides an Object initialized with the main constants defined
|
||||
* for this class. Use this as a fixture to avoid repetition.
|
||||
*
|
||||
* @return Object An initialized object.
|
||||
*/
|
||||
public function basicObjectFixture()
|
||||
{
|
||||
$o = new Object(self::FNAME);
|
||||
$o->setContent(self::FCONTENT, self::FTYPE);
|
||||
|
||||
/**
|
||||
* Set up a basic object fixture.
|
||||
*
|
||||
* This provides an Object initialized with the main constants defined
|
||||
* for this class. Use this as a fixture to avoid repetition.
|
||||
*
|
||||
* @return Object An initialized object.
|
||||
*/
|
||||
public function basicObjectFixture() {
|
||||
return $o;
|
||||
}
|
||||
|
||||
$o = new Object(self::FNAME);
|
||||
$o->setContent(self::FCONTENT, self::FTYPE);
|
||||
public function testConstructor()
|
||||
{
|
||||
$o = $this->basicObjectFixture();
|
||||
|
||||
return $o;
|
||||
}
|
||||
$this->assertEquals(self::FNAME, $o->name());
|
||||
|
||||
public function testConstructor() {
|
||||
$o = $this->basicObjectFixture();
|
||||
$o = new Object('a', 'b', 'text/plain');
|
||||
|
||||
$this->assertEquals(self::FNAME, $o->name());
|
||||
$this->assertEquals('a', $o->name());
|
||||
$this->assertEquals('b', $o->content());
|
||||
$this->assertEquals('text/plain', $o->contentType());
|
||||
}
|
||||
|
||||
$o = new Object('a', 'b', 'text/plain');
|
||||
public function testContentType()
|
||||
{
|
||||
// Don't use the fixture, we want to test content
|
||||
// type in its raw state.
|
||||
$o = new Object('foo.txt');
|
||||
|
||||
$this->assertEquals('a', $o->name());
|
||||
$this->assertEquals('b', $o->content());
|
||||
$this->assertEquals('text/plain', $o->contentType());
|
||||
}
|
||||
$this->assertEquals('application/octet-stream', $o->contentType());
|
||||
|
||||
public function testContentType() {
|
||||
// Don't use the fixture, we want to test content
|
||||
// type in its raw state.
|
||||
$o = new Object('foo.txt');
|
||||
$o->setContentType('text/plain; charset=UTF-8');
|
||||
$this->assertEquals('text/plain; charset=UTF-8', $o->contentType());
|
||||
}
|
||||
|
||||
$this->assertEquals('application/octet-stream', $o->contentType());
|
||||
public function testContent()
|
||||
{
|
||||
$o = $this->basicObjectFixture();
|
||||
|
||||
$o->setContentType('text/plain; charset=UTF-8');
|
||||
$this->assertEquals('text/plain; charset=UTF-8', $o->contentType());
|
||||
}
|
||||
$this->assertEquals(self::FCONTENT, $o->content());
|
||||
|
||||
public function testContent() {
|
||||
$o = $this->basicObjectFixture();
|
||||
// Test binary data.
|
||||
$bin = sha1(self::FCONTENT, TRUE);
|
||||
$o->setContent($bin, 'application/octet-stream');
|
||||
|
||||
$this->assertEquals(self::FCONTENT, $o->content());
|
||||
$this->assertEquals($bin, $o->content());
|
||||
}
|
||||
|
||||
// Test binary data.
|
||||
$bin = sha1(self::FCONTENT, TRUE);
|
||||
$o->setContent($bin, 'application/octet-stream');
|
||||
public function testEtag()
|
||||
{
|
||||
$o = $this->basicObjectFixture();
|
||||
$md5 = md5(self::FCONTENT);
|
||||
|
||||
$this->assertEquals($bin, $o->content());
|
||||
}
|
||||
$this->assertEquals($md5, $o->eTag());
|
||||
}
|
||||
|
||||
public function testEtag() {
|
||||
$o = $this->basicObjectFixture();
|
||||
$md5 = md5(self::FCONTENT);
|
||||
public function testIsChunked()
|
||||
{
|
||||
$o = $this->basicObjectFixture();
|
||||
$this->assertFalse($o->isChunked());
|
||||
}
|
||||
|
||||
$this->assertEquals($md5, $o->eTag());
|
||||
}
|
||||
public function testContentLength()
|
||||
{
|
||||
$o = $this->basicObjectFixture();
|
||||
$this->assertEquals(strlen(self::FCONTENT), $o->contentLength());
|
||||
|
||||
public function testIsChunked() {
|
||||
$o = $this->basicObjectFixture();
|
||||
$this->assertFalse($o->isChunked());
|
||||
}
|
||||
// Test on binary data.
|
||||
$bin = sha1(self::FCONTENT, TRUE);
|
||||
|
||||
public function testContentLength() {
|
||||
$o = $this->basicObjectFixture();
|
||||
$this->assertEquals(strlen(self::FCONTENT), $o->contentLength());
|
||||
$o->setContent($bin);
|
||||
$this->assertFalse($o->contentLength() == 0);
|
||||
$this->assertEquals(strlen($bin), $o->contentLength());
|
||||
}
|
||||
|
||||
// Test on binary data.
|
||||
$bin = sha1(self::FCONTENT, TRUE);
|
||||
public function testMetadata()
|
||||
{
|
||||
$md = array(
|
||||
'Immanuel' => 'Kant',
|
||||
'David' => 'Hume',
|
||||
'Gottfried' => 'Leibniz',
|
||||
'Jean-Jaques' => 'Rousseau',
|
||||
);
|
||||
|
||||
$o->setContent($bin);
|
||||
$this->assertFalse($o->contentLength() == 0);
|
||||
$this->assertEquals(strlen($bin), $o->contentLength());
|
||||
}
|
||||
$o = $this->basicObjectFixture();
|
||||
$o->setMetadata($md);
|
||||
|
||||
public function testMetadata() {
|
||||
$md = array(
|
||||
'Immanuel' => 'Kant',
|
||||
'David' => 'Hume',
|
||||
'Gottfried' => 'Leibniz',
|
||||
'Jean-Jaques' => 'Rousseau',
|
||||
);
|
||||
$got = $o->metadata();
|
||||
|
||||
$o = $this->basicObjectFixture();
|
||||
$o->setMetadata($md);
|
||||
$this->assertEquals(4, count($got));
|
||||
$this->assertArrayHasKey('Immanuel', $got);
|
||||
$this->assertEquals('Leibniz', $got['Gottfried']);
|
||||
|
||||
$got = $o->metadata();
|
||||
}
|
||||
|
||||
$this->assertEquals(4, count($got));
|
||||
$this->assertArrayHasKey('Immanuel', $got);
|
||||
$this->assertEquals('Leibniz', $got['Gottfried']);
|
||||
public function testAdditionalHeaders()
|
||||
{
|
||||
$o = $this->basicObjectFixture();
|
||||
|
||||
}
|
||||
$extra = array(
|
||||
'a' => 'b',
|
||||
'aaa' => 'bbb',
|
||||
'ccc' => 'bbb',
|
||||
);
|
||||
$o->setAdditionalHeaders($extra);
|
||||
|
||||
public function testAdditionalHeaders() {
|
||||
$o = $this->basicObjectFixture();
|
||||
$got = $o->additionalHeaders();
|
||||
$this->assertEquals(3, count($got));
|
||||
|
||||
$extra = array(
|
||||
'a' => 'b',
|
||||
'aaa' => 'bbb',
|
||||
'ccc' => 'bbb',
|
||||
);
|
||||
$o->setAdditionalHeaders($extra);
|
||||
$o->removeHeaders(array('ccc'));
|
||||
|
||||
$got = $o->additionalHeaders();
|
||||
$this->assertEquals(3, count($got));
|
||||
|
||||
$o->removeHeaders(array('ccc'));
|
||||
|
||||
|
||||
$got = $o->additionalHeaders();
|
||||
$this->assertEquals(2, count($got));
|
||||
}
|
||||
$got = $o->additionalHeaders();
|
||||
$this->assertEquals(2, count($got));
|
||||
}
|
||||
}
|
||||
|
@ -2,17 +2,17 @@
|
||||
/* ============================================================================
|
||||
(c) Copyright 2012-2014 Hewlett-Packard Development Company, L.P.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
============================================================================ */
|
||||
/**
|
||||
* Unit tests for ObjectStorage RemoteObject.
|
||||
@ -25,291 +25,308 @@ use \OpenStack\Storage\ObjectStorage\RemoteObject;
|
||||
use \OpenStack\Storage\ObjectStorage\Object;
|
||||
use \OpenStack\Storage\ObjectStorage\Container;
|
||||
|
||||
class RemoteObjectTest extends \OpenStack\Tests\TestCase {
|
||||
|
||||
const FNAME = 'RemoteObjectTest';
|
||||
//const FTYPE = 'text/plain; charset=UTF-8';
|
||||
const FTYPE = 'application/octet-stream; charset=UTF-8';
|
||||
const FCONTENT = 'Rah rah ah ah ah. Roma roma ma. Gaga oh la la.';
|
||||
const FMETA_NAME = 'Foo';
|
||||
const FMETA_VALUE = 'Bar';
|
||||
const FDISPOSITION = 'attachment; roma.gaga';
|
||||
const FENCODING = 'gzip';
|
||||
const FCORS_NAME = 'Access-Control-Max-Age';
|
||||
const FCORS_VALUE = '2000';
|
||||
|
||||
protected function createAnObject() {
|
||||
$container = $this->containerFixture();
|
||||
|
||||
$object = new Object(self::FNAME, self::FCONTENT, self::FTYPE);
|
||||
$object->setMetadata(array(self::FMETA_NAME => self::FMETA_VALUE));
|
||||
$object->setDisposition(self::FDISPOSITION);
|
||||
$object->setEncoding(self::FENCODING);
|
||||
$object->setAdditionalHeaders(array(
|
||||
'Access-Control-Allow-Origin' => 'http://example.com',
|
||||
'Access-control-allow-origin' => 'http://example.com',
|
||||
));
|
||||
|
||||
// Need some headers that Swift actually stores and returns. This
|
||||
// one does not seem to be returned ever.
|
||||
//$object->setAdditionalHeaders(array(self::FCORS_NAME => self::FCORS_VALUE));
|
||||
|
||||
$container->save($object);
|
||||
}
|
||||
|
||||
public function testNewFromHeaders() {
|
||||
// This is tested via the container.
|
||||
|
||||
$this->destroyContainerFixture();
|
||||
$container = $this->containerFixture();
|
||||
$this->createAnObject();
|
||||
|
||||
$obj = $container->remoteObject(self::FNAME);
|
||||
|
||||
$this->assertInstanceOf('\OpenStack\Storage\ObjectStorage\RemoteObject', $obj);
|
||||
|
||||
return $obj;
|
||||
}
|
||||
/**
|
||||
* @depends testNewFromHeaders
|
||||
*/
|
||||
public function testContentLength($obj) {
|
||||
$len = strlen(self::FCONTENT);
|
||||
|
||||
$this->assertEquals($len, $obj->contentLength());
|
||||
|
||||
return $obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testContentLength
|
||||
*/
|
||||
public function testContentType($obj) {
|
||||
$this->assertEquals(self::FTYPE, $obj->contentType());
|
||||
class RemoteObjectTest extends \OpenStack\Tests\TestCase
|
||||
{
|
||||
const FNAME = 'RemoteObjectTest';
|
||||
//const FTYPE = 'text/plain; charset=UTF-8';
|
||||
const FTYPE = 'application/octet-stream; charset=UTF-8';
|
||||
const FCONTENT = 'Rah rah ah ah ah. Roma roma ma. Gaga oh la la.';
|
||||
const FMETA_NAME = 'Foo';
|
||||
const FMETA_VALUE = 'Bar';
|
||||
const FDISPOSITION = 'attachment; roma.gaga';
|
||||
const FENCODING = 'gzip';
|
||||
const FCORS_NAME = 'Access-Control-Max-Age';
|
||||
const FCORS_VALUE = '2000';
|
||||
|
||||
protected function createAnObject()
|
||||
{
|
||||
$container = $this->containerFixture();
|
||||
|
||||
$object = new Object(self::FNAME, self::FCONTENT, self::FTYPE);
|
||||
$object->setMetadata(array(self::FMETA_NAME => self::FMETA_VALUE));
|
||||
$object->setDisposition(self::FDISPOSITION);
|
||||
$object->setEncoding(self::FENCODING);
|
||||
$object->setAdditionalHeaders(array(
|
||||
'Access-Control-Allow-Origin' => 'http://example.com',
|
||||
'Access-control-allow-origin' => 'http://example.com',
|
||||
));
|
||||
|
||||
// Need some headers that Swift actually stores and returns. This
|
||||
// one does not seem to be returned ever.
|
||||
//$object->setAdditionalHeaders(array(self::FCORS_NAME => self::FCORS_VALUE));
|
||||
|
||||
$container->save($object);
|
||||
}
|
||||
|
||||
public function testNewFromHeaders()
|
||||
{
|
||||
// This is tested via the container.
|
||||
|
||||
$this->destroyContainerFixture();
|
||||
$container = $this->containerFixture();
|
||||
$this->createAnObject();
|
||||
|
||||
$obj = $container->remoteObject(self::FNAME);
|
||||
|
||||
$this->assertInstanceOf('\OpenStack\Storage\ObjectStorage\RemoteObject', $obj);
|
||||
|
||||
return $obj;
|
||||
}
|
||||
/**
|
||||
* @depends testNewFromHeaders
|
||||
*/
|
||||
public function testContentLength($obj)
|
||||
{
|
||||
$len = strlen(self::FCONTENT);
|
||||
|
||||
$this->assertEquals($len, $obj->contentLength());
|
||||
|
||||
return $obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testContentLength
|
||||
*/
|
||||
public function testContentType($obj)
|
||||
{
|
||||
$this->assertEquals(self::FTYPE, $obj->contentType());
|
||||
|
||||
return $obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testContentType
|
||||
*/
|
||||
public function testEtag($obj)
|
||||
{
|
||||
$hash = md5(self::FCONTENT);
|
||||
|
||||
$this->assertEquals($hash, $obj->eTag());
|
||||
|
||||
return $obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testContentType
|
||||
*/
|
||||
public function testLastModified($obj)
|
||||
{
|
||||
$date = $obj->lastModified();
|
||||
|
||||
$this->assertTrue(is_int($date));
|
||||
$this->assertTrue($date > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testNewFromHeaders
|
||||
*/
|
||||
public function testMetadata($obj)
|
||||
{
|
||||
$md = $obj->metadata();
|
||||
|
||||
$this->assertArrayHasKey(self::FMETA_NAME, $md);
|
||||
$this->assertEquals(self::FMETA_VALUE, $md[self::FMETA_NAME]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testNewFromHeaders
|
||||
*/
|
||||
public function testDisposition($obj)
|
||||
{
|
||||
$this->assertEquals(self::FDISPOSITION, $obj->disposition());
|
||||
}
|
||||
|
||||
return $obj;
|
||||
}
|
||||
/**
|
||||
* @depends testNewFromHeaders
|
||||
*/
|
||||
public function testEncoding($obj)
|
||||
{
|
||||
$this->assertEquals(self::FENCODING, $obj->encoding());
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testContentType
|
||||
*/
|
||||
public function testEtag($obj) {
|
||||
$hash = md5(self::FCONTENT);
|
||||
/**
|
||||
* @depends testNewFromHeaders
|
||||
*/
|
||||
public function testHeaders($obj)
|
||||
{
|
||||
$headers = $obj->headers();
|
||||
$this->assertTrue(count($headers) > 1);
|
||||
|
||||
$this->assertEquals($hash, $obj->eTag());
|
||||
//fwrite(STDOUT, print_r($headers, TRUE));
|
||||
|
||||
return $obj;
|
||||
}
|
||||
$this->assertNotEmpty($headers['Date']);
|
||||
|
||||
/**
|
||||
* @depends testContentType
|
||||
*/
|
||||
public function testLastModified($obj) {
|
||||
$date = $obj->lastModified();
|
||||
$obj->removeHeaders(array('Date'));
|
||||
|
||||
$this->assertTrue(is_int($date));
|
||||
$this->assertTrue($date > 0);
|
||||
}
|
||||
$headers = $obj->headers();
|
||||
$this->assertFalse(isset($headers['Date']));
|
||||
|
||||
/**
|
||||
* @depends testNewFromHeaders
|
||||
*/
|
||||
public function testMetadata($obj) {
|
||||
$md = $obj->metadata();
|
||||
// Swift doesn't return CORS headers even though it is supposed to.
|
||||
//$this->assertEquals(self::FCORS_VALUE, $headers[self::FCORS_NAME]);
|
||||
}
|
||||
|
||||
$this->assertArrayHasKey(self::FMETA_NAME, $md);
|
||||
$this->assertEquals(self::FMETA_VALUE, $md[self::FMETA_NAME]);
|
||||
}
|
||||
/**
|
||||
* @depends testNewFromHeaders
|
||||
*/
|
||||
public function testUrl($obj)
|
||||
{
|
||||
$url = $obj->url();
|
||||
|
||||
/**
|
||||
* @depends testNewFromHeaders
|
||||
*/
|
||||
public function testDisposition($obj) {
|
||||
$this->assertEquals(self::FDISPOSITION, $obj->disposition());
|
||||
}
|
||||
$this->assertTrue(strpos($obj->url(), $obj->name())> 0);
|
||||
}
|
||||
/**
|
||||
* @depends testNewFromHeaders
|
||||
*/
|
||||
public function testStream($obj)
|
||||
{
|
||||
$res = $obj->stream();
|
||||
|
||||
/**
|
||||
* @depends testNewFromHeaders
|
||||
*/
|
||||
public function testEncoding($obj) {
|
||||
$this->assertEquals(self::FENCODING, $obj->encoding());
|
||||
}
|
||||
$this->assertTrue(is_resource($res));
|
||||
|
||||
/**
|
||||
* @depends testNewFromHeaders
|
||||
*/
|
||||
public function testHeaders($obj) {
|
||||
$headers = $obj->headers();
|
||||
$this->assertTrue(count($headers) > 1);
|
||||
$res_md = stream_get_meta_data($res);
|
||||
|
||||
$content = fread($res, $obj->contentLength());
|
||||
|
||||
fclose($res);
|
||||
|
||||
//fwrite(STDOUT, print_r($headers, TRUE));
|
||||
$this->assertEquals(self::FCONTENT, $content);
|
||||
|
||||
$this->assertNotEmpty($headers['Date']);
|
||||
// Now repeat the tests, only with a local copy of the data.
|
||||
// This allows us to test the local tempfile buffering.
|
||||
|
||||
$obj->removeHeaders(array('Date'));
|
||||
$obj->setContent($content);
|
||||
|
||||
$headers = $obj->headers();
|
||||
$this->assertFalse(isset($headers['Date']));
|
||||
$res2 = $obj->stream();
|
||||
$res_md = stream_get_meta_data($res2);
|
||||
|
||||
// Swift doesn't return CORS headers even though it is supposed to.
|
||||
//$this->assertEquals(self::FCORS_VALUE, $headers[self::FCORS_NAME]);
|
||||
}
|
||||
$this->assertEquals('PHP', $res_md['wrapper_type']);
|
||||
|
||||
/**
|
||||
* @depends testNewFromHeaders
|
||||
*/
|
||||
public function testUrl($obj) {
|
||||
$url = $obj->url();
|
||||
$content = fread($res2, $obj->contentLength());
|
||||
|
||||
$this->assertTrue(strpos($obj->url(), $obj->name())> 0);
|
||||
}
|
||||
/**
|
||||
* @depends testNewFromHeaders
|
||||
*/
|
||||
public function testStream($obj) {
|
||||
$res = $obj->stream();
|
||||
fclose($res2);
|
||||
|
||||
$this->assertTrue(is_resource($res));
|
||||
$this->assertEquals(self::FCONTENT, $content);
|
||||
|
||||
$res_md = stream_get_meta_data($res);
|
||||
// Finally, we redo the first part of the test to make sure that
|
||||
// refreshing gets us a new copy:
|
||||
|
||||
$content = fread($res, $obj->contentLength());
|
||||
$res3 = $obj->stream(TRUE);
|
||||
$res_md = stream_get_meta_data($res3);
|
||||
$this->assertEquals('PHP', $res_md['wrapper_type']);
|
||||
fclose($res3);
|
||||
|
||||
fclose($res);
|
||||
return $obj;
|
||||
}
|
||||
|
||||
$this->assertEquals(self::FCONTENT, $content);
|
||||
// To avoid test tainting from testStream(), we start over.
|
||||
public function testContent()
|
||||
{
|
||||
$container = $this->containerFixture();
|
||||
$obj = $container->object(self::FNAME);
|
||||
|
||||
// Now repeat the tests, only with a local copy of the data.
|
||||
// This allows us to test the local tempfile buffering.
|
||||
$content = $obj->content();
|
||||
$this->assertEquals(self::FCONTENT, $content);
|
||||
|
||||
$obj->setContent($content);
|
||||
// Make sure remoteObject retrieves the same content.
|
||||
$obj = $container->remoteObject(self::FNAME);
|
||||
$content = $obj->content();
|
||||
$this->assertEquals(self::FCONTENT, $content);
|
||||
|
||||
$res2 = $obj->stream();
|
||||
$res_md = stream_get_meta_data($res2);
|
||||
}
|
||||
|
||||
$this->assertEquals('PHP', $res_md['wrapper_type']);
|
||||
/**
|
||||
* @depends testStream
|
||||
*/
|
||||
public function testCaching()
|
||||
{
|
||||
$container = $this->containerFixture();
|
||||
$obj = $container->remoteObject(self::FNAME);
|
||||
|
||||
$content = fread($res2, $obj->contentLength());
|
||||
$this->assertFalse($obj->isCaching());
|
||||
|
||||
fclose($res2);
|
||||
$content = $obj->content();
|
||||
|
||||
$this->assertEquals(self::FCONTENT, $content);
|
||||
$res1 = $obj->stream();
|
||||
$md = stream_get_meta_data($res1);
|
||||
$this->assertEquals('PHP', $md['wrapper_type']);
|
||||
|
||||
// Finally, we redo the first part of the test to make sure that
|
||||
// refreshing gets us a new copy:
|
||||
fclose($res1);
|
||||
|
||||
$res3 = $obj->stream(TRUE);
|
||||
$res_md = stream_get_meta_data($res3);
|
||||
$this->assertEquals('PHP', $res_md['wrapper_type']);
|
||||
fclose($res3);
|
||||
// Enable caching and retest.
|
||||
$obj->setCaching(TRUE);
|
||||
$this->assertTrue($obj->isCaching());
|
||||
|
||||
return $obj;
|
||||
}
|
||||
// This will cache the content.
|
||||
$content = $obj->content();
|
||||
|
||||
// To avoid test tainting from testStream(), we start over.
|
||||
public function testContent() {
|
||||
$container = $this->containerFixture();
|
||||
$obj = $container->object(self::FNAME);
|
||||
$res2 = $obj->stream();
|
||||
$md = stream_get_meta_data($res2);
|
||||
|
||||
$content = $obj->content();
|
||||
$this->assertEquals(self::FCONTENT, $content);
|
||||
// If this is using the PHP version, it built content from the
|
||||
// cached version.
|
||||
$this->assertEquals('PHP', $md['wrapper_type']);
|
||||
|
||||
// Make sure remoteObject retrieves the same content.
|
||||
$obj = $container->remoteObject(self::FNAME);
|
||||
$content = $obj->content();
|
||||
$this->assertEquals(self::FCONTENT, $content);
|
||||
fclose($res2);
|
||||
}
|
||||
|
||||
}
|
||||
/**
|
||||
* @depends testNewFromHeaders
|
||||
*/
|
||||
public function testContentVerification($obj)
|
||||
{
|
||||
$this->assertTrue($obj->isVerifyingContent());
|
||||
$obj->setContentVerification(FALSE);
|
||||
$this->assertFALSE($obj->isVerifyingContent());
|
||||
$obj->setContentVerification(TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testStream
|
||||
*/
|
||||
public function testCaching() {
|
||||
$container = $this->containerFixture();
|
||||
$obj = $container->remoteObject(self::FNAME);
|
||||
/**
|
||||
* @depends testCaching
|
||||
*/
|
||||
public function testIsDirty()
|
||||
{
|
||||
$container = $this->containerFixture();
|
||||
$obj = $container->remoteObject(self::FNAME);
|
||||
|
||||
$this->assertFalse($obj->isCaching());
|
||||
// THere is no content. Assert false.
|
||||
$this->assertFalse($obj->isDirty());
|
||||
|
||||
$content = $obj->content();
|
||||
$obj->setCaching(TRUE);
|
||||
$obj->content();
|
||||
|
||||
$res1 = $obj->stream();
|
||||
$md = stream_get_meta_data($res1);
|
||||
$this->assertEquals('PHP', $md['wrapper_type']);
|
||||
// THere is content, but it is unchanged.
|
||||
$this->assertFalse($obj->isDirty());
|
||||
|
||||
fclose($res1);
|
||||
// Change content and retest.
|
||||
$obj->setContent('foo');
|
||||
|
||||
// Enable caching and retest.
|
||||
$obj->setCaching(TRUE);
|
||||
$this->assertTrue($obj->isCaching());
|
||||
$this->assertTrue($obj->isDirty());
|
||||
}
|
||||
|
||||
// This will cache the content.
|
||||
$content = $obj->content();
|
||||
/**
|
||||
* @depends testIsDirty
|
||||
*/
|
||||
public function testRefresh()
|
||||
{
|
||||
$container = $this->containerFixture();
|
||||
$obj = $container->remoteObject(self::FNAME);
|
||||
|
||||
$res2 = $obj->stream();
|
||||
$md = stream_get_meta_data($res2);
|
||||
$obj->setContent('foo');
|
||||
$this->assertTrue($obj->isDirty());
|
||||
|
||||
// If this is using the PHP version, it built content from the
|
||||
// cached version.
|
||||
$this->assertEquals('PHP', $md['wrapper_type']);
|
||||
$obj->refresh(FALSE);
|
||||
$this->assertFalse($obj->isDirty());
|
||||
$this->assertEquals(self::FCONTENT, $obj->content());
|
||||
|
||||
fclose($res2);
|
||||
}
|
||||
$obj->setContent('foo');
|
||||
$this->assertTrue($obj->isDirty());
|
||||
|
||||
/**
|
||||
* @depends testNewFromHeaders
|
||||
*/
|
||||
public function testContentVerification($obj) {
|
||||
$this->assertTrue($obj->isVerifyingContent());
|
||||
$obj->setContentVerification(FALSE);
|
||||
$this->assertFALSE($obj->isVerifyingContent());
|
||||
$obj->setContentVerification(TRUE);
|
||||
}
|
||||
$obj->refresh(TRUE);
|
||||
$this->assertFalse($obj->isDirty());
|
||||
$this->assertEquals(self::FCONTENT, $obj->content());
|
||||
|
||||
/**
|
||||
* @depends testCaching
|
||||
*/
|
||||
public function testIsDirty() {
|
||||
$container = $this->containerFixture();
|
||||
$obj = $container->remoteObject(self::FNAME);
|
||||
$this->destroyContainerFixture();
|
||||
|
||||
// THere is no content. Assert false.
|
||||
$this->assertFalse($obj->isDirty());
|
||||
|
||||
$obj->setCaching(TRUE);
|
||||
$obj->content();
|
||||
|
||||
// THere is content, but it is unchanged.
|
||||
$this->assertFalse($obj->isDirty());
|
||||
|
||||
// Change content and retest.
|
||||
$obj->setContent('foo');
|
||||
|
||||
$this->assertTrue($obj->isDirty());
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testIsDirty
|
||||
*/
|
||||
public function testRefresh() {
|
||||
$container = $this->containerFixture();
|
||||
$obj = $container->remoteObject(self::FNAME);
|
||||
|
||||
$obj->setContent('foo');
|
||||
$this->assertTrue($obj->isDirty());
|
||||
|
||||
$obj->refresh(FALSE);
|
||||
$this->assertFalse($obj->isDirty());
|
||||
$this->assertEquals(self::FCONTENT, $obj->content());
|
||||
|
||||
$obj->setContent('foo');
|
||||
$this->assertTrue($obj->isDirty());
|
||||
|
||||
$obj->refresh(TRUE);
|
||||
$this->assertFalse($obj->isDirty());
|
||||
$this->assertEquals(self::FCONTENT, $obj->content());
|
||||
|
||||
$this->destroyContainerFixture();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -2,22 +2,22 @@
|
||||
/* ============================================================================
|
||||
(c) Copyright 2012-2014 Hewlett-Packard Development Company, L.P.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
============================================================================ */
|
||||
/**
|
||||
* Helpers for testing using the CurlTransport.
|
||||
*/
|
||||
|
||||
$bootstrap_settings = array(
|
||||
'transport' => '\OpenStack\Transport\CURLTransport',
|
||||
'transport' => '\OpenStack\Transport\CURLTransport',
|
||||
);
|
||||
|
@ -2,22 +2,22 @@
|
||||
/* ============================================================================
|
||||
(c) Copyright 2012-2014 Hewlett-Packard Development Company, L.P.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
============================================================================ */
|
||||
/**
|
||||
* Helpers for testing using the CurlTransport.
|
||||
*/
|
||||
|
||||
$bootstrap_settings = array(
|
||||
'transport' => '\OpenStack\Transport\PHPStreamTransport',
|
||||
'transport' => '\OpenStack\Transport\PHPStreamTransport',
|
||||
);
|
||||
|
Loading…
x
Reference in New Issue
Block a user