diff --git a/.gitignore b/.gitignore index 19ad2fe..d719482 100644 --- a/.gitignore +++ b/.gitignore @@ -199,3 +199,6 @@ Makefile* .DS_Store composer.lock PHP-Parser*/ +src/*.so +src/*.dylib +src/*.dll diff --git a/Makefile.frag b/Makefile.frag index 4a01adb..1df88a3 100644 --- a/Makefile.frag +++ b/Makefile.frag @@ -4,6 +4,7 @@ DEPS_DIR=$(BUILD_DIR)/deps INT_DIR=$(BUILD_DIR)/install INSTALL_DIR=$(shell pwd) GENERATE_STUBS=$(shell expr `php --version | head -1 | cut -f 2 -d' '` \>= 7.1) +HAS_FFI=$(shell php -m | grep FFI | wc -l | xargs) CMAKE = cmake3 ifeq (, $(shell which cmake3)) @@ -15,13 +16,8 @@ CMAKE_BUILD = $(CMAKE) --build CMAKE_BUILD_TYPE ?= RelWithDebInfo CMAKE_TARGET = --config $(CMAKE_BUILD_TYPE) --target install -# configure for shared aws-crt-ffi.so -$(BUILD_DIR)/aws-crt-ffi-shared/CMakeCache.txt: - $(CMAKE_CONFIGURE) -Hcrt/aws-crt-ffi -Bbuild/aws-crt-ffi-shared -DBUILD_SHARED_LIBS=ON - -# build shared libaws-crt-ffi.so -$(BUILD_DIR)/aws-crt-ffi-shared/libaws-crt-ffi.so: $(BUILD_DIR)/aws-crt-ffi-shared/CMakeCache.txt - $(CMAKE_BUILD) build/aws-crt-ffi-shared $(CMAKE_TARGET) +all: extension ffi +.PHONY: all extension ffi # configure for static aws-crt-ffi.a $(BUILD_DIR)/aws-crt-ffi-static/CMakeCache.txt: @@ -32,7 +28,7 @@ $(BUILD_DIR)/aws-crt-ffi-static/libaws-crt-ffi.a: $(BUILD_DIR)/aws-crt-ffi-stati $(CMAKE_BUILD) build/aws-crt-ffi-static $(CMAKE_TARGET) # PHP extension target -awscrt: ext/awscrt.lo +extension: ext/awscrt.lo # Force the crt object target to depend on the CRT static library ext/awscrt.lo: ext/awscrt.c @@ -56,13 +52,37 @@ ext/api.h : src/api.h ext/php_aws_crt.h: ext/awscrt_arginfo.h ext/api.h # FFI target -ffi: src/libaws-crt-ffi.so +ffi: src/api.h src/libaws-crt-ffi.$(SHLIB_SUFFIX_NAME) + +# configure for shared aws-crt-ffi.so +$(BUILD_DIR)/aws-crt-ffi-shared/CMakeCache.txt: +ifeq ($(HAS_FFI),1) + $(CMAKE_CONFIGURE) -Hcrt/aws-crt-ffi -Bbuild/aws-crt-ffi-shared -DBUILD_SHARED_LIBS=ON +endif + +# build shared libaws-crt-ffi.so +$(BUILD_DIR)/aws-crt-ffi-shared/libaws-crt-ffi.$(SHLIB_SUFFIX_NAME): $(BUILD_DIR)/aws-crt-ffi-shared/CMakeCache.txt +ifeq ($(HAS_FFI),1) + $(CMAKE_BUILD) build/aws-crt-ffi-shared $(CMAKE_TARGET) +endif # copy the lib into the src folder -modules/libaws-crt-ffi.so: $(BUILD_DIR)/aws-crt-ffi-shared/libaws-crt-ffi.so src/api.h - cp -v $(BUILD_DIR)/aws-crt-ffi-shared/libaws-crt-ffi.so modules/libaws-crt-ffi.so +src/libaws-crt-ffi.$(SHLIB_SUFFIX_NAME): $(BUILD_DIR)/aws-crt-ffi-shared/libaws-crt-ffi.$(SHLIB_SUFFIX_NAME) src/api.h +ifeq ($(HAS_FFI),1) + cp -v $(BUILD_DIR)/aws-crt-ffi-shared/libaws-crt-ffi.$(SHLIB_SUFFIX_NAME) src/libaws-crt-ffi.$(SHLIB_SUFFIX_NAME) +endif + +vendor/bin/phpunit: + composer update + +test-ffi: vendor/bin/phpunit ffi +ifeq ($(HAS_FFI),1) + AWS_CRT_PHP_FFI=1 composer run test-ffi +endif + +test-extension: vendor/bin/phpunit extension + AWS_CRT_PHP_EXTENSION=1 composer run test-extension # Use PHPUnit to run tests -test: ext/api.h ext/awscrt_arginfo.h ext/awscrt.lo - composer update - composer run test +test: test-ffi test-extension + diff --git a/builder.json b/builder.json index d57286e..859a0ea 100644 --- a/builder.json +++ b/builder.json @@ -32,6 +32,6 @@ "NO_INTERACTION": "1" }, "test_steps": [ - ["make", "test"] + ["./ci-test.sh"] ] } diff --git a/ci-test.sh b/ci-test.sh new file mode 100755 index 0000000..6faf1b5 --- /dev/null +++ b/ci-test.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash + +set -ex + +HAS_FFI=$(php -m | grep FFI | wc -l | xargs) + +make test-extension + +if [[ $HAS_FFI -gt 0 ]]; then + make test-ffi +fi \ No newline at end of file diff --git a/composer.json b/composer.json index e00c270..5a082e8 100644 --- a/composer.json +++ b/composer.json @@ -29,7 +29,9 @@ ] }, "scripts": { - "test": "@php -d extension=modules/awscrt.so vendor/bin/phpunit tests" + "test": "@php -d extension=modules/awscrt.so vendor/bin/phpunit tests", + "test-extension": "@php -d extension=modules/awscrt.so vendor/bin/phpunit tests", + "test-ffi": "@php vendor/bin/phpunit tests" }, "license": "Apache-2.0" } diff --git a/ext/signing.c b/ext/signing.c index bb1188f..124da0c 100644 --- a/ext/signing.c +++ b/ext/signing.c @@ -258,8 +258,9 @@ PHP_FUNCTION(aws_crt_sign_request_aws) { zend_ulong php_signable = 0; zend_ulong php_signing_config = 0; zval *php_on_complete = 0; + zend_ulong php_user_data = 0; - aws_php_parse_parameters("llz", &php_signable, &php_signing_config, &php_on_complete); + aws_php_parse_parameters("llzl", &php_signable, &php_signing_config, &php_on_complete, &php_user_data); aws_crt_signable *signable = (void *)php_signable; aws_crt_signing_config_aws *signing_config = (void *)php_signing_config; diff --git a/src/AWS/CRT/Auth/Signing.php b/src/AWS/CRT/Auth/Signing.php index ff949aa..a762590 100644 --- a/src/AWS/CRT/Auth/Signing.php +++ b/src/AWS/CRT/Auth/Signing.php @@ -13,6 +13,6 @@ abstract class Signing extends NativeResource { function($result, $error_code) use ($on_complete) { $signing_result = SigningResult::fromNative($result); $on_complete($signing_result, $error_code); - }); + }, null); } } \ No newline at end of file diff --git a/src/AWS/CRT/CRT.php b/src/AWS/CRT/CRT.php index 8531729..c0eddb7 100644 --- a/src/AWS/CRT/CRT.php +++ b/src/AWS/CRT/CRT.php @@ -24,6 +24,14 @@ final class CRT { if (is_null(self::$impl)) { // Figure out what backends are/should be available $backends = ['Extension']; + if (extension_loaded('ffi')) { + $backends = ['Extension', 'FFI']; + if (getenv('AWS_CRT_PHP_EXTENSION')) { + $backends = ['Extension']; + } else if (getenv('AWS_CRT_PHP_FFI')) { + $backends = ['FFI']; + } + } // Try to load each backend, give up if none succeed $exceptions = []; @@ -31,6 +39,7 @@ final class CRT { try { $backend = 'AWS\\CRT\\Internal\\' . $backend; self::$impl = new $backend(); + break; } catch (RuntimeException $rex) { array_push($exceptions, $rex); } @@ -67,6 +76,20 @@ final class CRT { } } + /** + * @return bool true if using PHP FFI (PHP 7.4+) + */ + public static function isFFI() { + return self::isLoaded() && strstr(get_class(self::$impl), 'FFI'); + } + + /** + * @return bool true if using PHP Extension awscrt + */ + public static function isExtension() { + return self::isLoaded() && strstr(get_class(self::$impl), 'Extension'); + } + /** * @return integer last error code reported within the CRT */ @@ -319,7 +342,7 @@ final class CRT { $signing_result, $http_message); } - function sign_request_aws($signable, $signing_config, $on_complete) { - return self::$impl->aws_crt_sign_request_aws($signable, $signing_config, $on_complete); + function sign_request_aws($signable, $signing_config, $on_complete, $user_data) { + return self::$impl->aws_crt_sign_request_aws($signable, $signing_config, $on_complete, $user_data); } } diff --git a/src/AWS/CRT/Internal/FFI.php b/src/AWS/CRT/Internal/FFI.php new file mode 100644 index 0000000..ad1ac87 --- /dev/null +++ b/src/AWS/CRT/Internal/FFI.php @@ -0,0 +1,82 @@ + 0) { + $uint8_t = \FFI::type('uint8_t'); + $uint8_array = \FFI::arrayType($uint8_t, [$len]); + $buf = \FFI::new($uint8_array); + \FFI::memcpy($buf, $arg, $len); + $ffi_args [] = $buf; + $ffi_args [] = $len; + } else { + $ffi_args [] = null; + $ffi_args [] = 0; + } + } else if (is_resource($arg)) { + throw new RuntimeException("Resource types are not supported for FFI"); + } else { + $ffi_args []= $arg; + } + } + return call_user_func_array([self::$ffi, $name], $ffi_args); + } + + private static function init() { + return self::$ffi->aws_crt_init(); + } + + private static function clean_up() { + return self::$ffi->aws_crt_clean_up(); + } +} diff --git a/tests/SigningTest.php b/tests/SigningTest.php index 8b1ecc0..ac84b9d 100644 --- a/tests/SigningTest.php +++ b/tests/SigningTest.php @@ -39,6 +39,7 @@ final class SigningTest extends CrtTestCase { } public function testSignableFromChunkLifetime() { + $this->skipFFI(); $chunk = "THIS IS A TEST CHUNK IT CONTAINS MULTITUDES"; $stream = fopen("php://memory", 'r+'); fputs($stream, $chunk); @@ -61,6 +62,8 @@ final class SigningTest extends CrtTestCase { const SIGV4TEST_SERVICE = 'service'; const SIGV4TEST_REGION = 'us-east-1'; public function testSigv4HeaderSigning() { + $this->skipFFI(); + $date = mktime(12, 36, 0, 8, 30, 2015); $credentials_provider = new StaticCredentialsProvider([ 'access_key_id' => self::SIGV4TEST_ACCESS_KEY_ID, diff --git a/tests/StreamTest.php b/tests/StreamTest.php index f8a116a..9c090a0 100644 --- a/tests/StreamTest.php +++ b/tests/StreamTest.php @@ -19,6 +19,7 @@ final class InputStreamTest extends CrtTestCase { } public function testMemoryStream() { + $this->skipFFI(); $mem_stream = $this->getMemoryStream(); $stream = new InputStream($mem_stream); $this->assertNotNull($stream, "Failed to create InputStream from PHP memory stream"); diff --git a/tests/common.inc b/tests/common.inc index db1e199..391a475 100644 --- a/tests/common.inc +++ b/tests/common.inc @@ -29,4 +29,10 @@ abstract class CrtTestCase extends PHPUnit_Framework_TestCase { $this->setExpectedException($arguments[0]); } } + + public function skipFFI() { + if (CRT::isFFI()) { + $this->markTestSkipped(); + } + } }