diff options
author | kufd <kosinski@ukr.net> | 2017-03-19 19:48:50 +0200 |
---|---|---|
committer | James E. King, III <jking@apache.org> | 2017-03-30 16:42:11 -0400 |
commit | 1360270eb8e03402d48322514eaa58342e5b25d0 (patch) | |
tree | 01e53bce495ade0a3db3eef3b1f16669a2f7e4af /lib/php | |
parent | 7470995ce4bb480a86beaf1d8babce95c6f4b8c7 (diff) | |
download | thrift-1360270eb8e03402d48322514eaa58342e5b25d0.tar.gz |
THRIFT-4126: implement required fields validation in php extension when validate compiler option is enabled
Client: php
This closes #1215
Diffstat (limited to 'lib/php')
-rw-r--r-- | lib/php/src/ext/thrift_protocol/php_thrift_protocol.cpp | 44 | ||||
-rw-r--r-- | lib/php/src/ext/thrift_protocol/php_thrift_protocol7.cpp | 42 |
2 files changed, 85 insertions, 1 deletions
diff --git a/lib/php/src/ext/thrift_protocol/php_thrift_protocol.cpp b/lib/php/src/ext/thrift_protocol/php_thrift_protocol.cpp index f9b3ad76e..4c9062e80 100644 --- a/lib/php/src/ext/thrift_protocol/php_thrift_protocol.cpp +++ b/lib/php/src/ext/thrift_protocol/php_thrift_protocol.cpp @@ -728,6 +728,42 @@ inline bool ttypes_are_compatible(int8_t t1, int8_t t2) { return ((t1 == t2) || (ttype_is_int(t1) && ttype_is_int(t2))); } +//is used to validate objects before serialization and after deserialization. For now, only required fields are validated. +static +void validate_thrift_object(zval* object) { + + HashPosition key_ptr; + zval** val_ptr; + + TSRMLS_FETCH(); + zend_class_entry* object_class_entry = zend_get_class_entry(object TSRMLS_CC); + HashTable* spec = Z_ARRVAL_P(zend_read_static_property(object_class_entry, "_TSPEC", 6, false TSRMLS_CC)); + + for (zend_hash_internal_pointer_reset_ex(spec, &key_ptr); zend_hash_get_current_data_ex(spec, (void**)&val_ptr, &key_ptr) == SUCCESS; zend_hash_move_forward_ex(spec, &key_ptr)) { + ulong fieldno; + if (zend_hash_get_current_key_ex(spec, NULL, NULL, &fieldno, 0, &key_ptr) != HASH_KEY_IS_LONG) { + throw_tprotocolexception("Bad keytype in TSPEC (expected 'long')", INVALID_DATA); + return; + } + HashTable* fieldspec = Z_ARRVAL_PP(val_ptr); + + // field name + zend_hash_find(fieldspec, "var", 4, (void**)&val_ptr); + char* varname = Z_STRVAL_PP(val_ptr); + + zend_hash_find(fieldspec, "isRequired", 11, (void**)&val_ptr); + bool is_required = Z_BVAL_PP(val_ptr); + + zval* prop = zend_read_property(object_class_entry, object, varname, strlen(varname), false TSRMLS_CC); + + if (is_required && Z_TYPE_P(prop) == IS_NULL) { + char errbuf[128]; + snprintf(errbuf, 128, "Required field %s.%s is unset!", object_class_entry->name, varname); + throw_tprotocolexception(errbuf, INVALID_DATA); + } + } +} + void binary_deserialize_spec(zval* zthis, PHPInputTransport& transport, HashTable* spec) { // SET and LIST have 'elem' => array('type', [optional] 'class') // MAP has 'val' => array('type', [optiona] 'class') @@ -737,7 +773,10 @@ void binary_deserialize_spec(zval* zthis, PHPInputTransport& transport, HashTabl zval** val_ptr = NULL; int8_t ttype = transport.readI8(); - if (ttype == T_STOP) return; + if (ttype == T_STOP) { + validate_thrift_object(zthis); + return; + } int16_t fieldno = transport.readI16(); if (zend_hash_index_find(spec, fieldno, (void**)&val_ptr) == SUCCESS) { HashTable* fieldspec = Z_ARRVAL_PP(val_ptr); @@ -903,6 +942,9 @@ void binary_serialize(int8_t thrift_typeID, PHPOutputTransport& transport, zval* void binary_serialize_spec(zval* zthis, PHPOutputTransport& transport, HashTable* spec) { + + validate_thrift_object(zthis); + HashPosition key_ptr; zval** val_ptr; diff --git a/lib/php/src/ext/thrift_protocol/php_thrift_protocol7.cpp b/lib/php/src/ext/thrift_protocol/php_thrift_protocol7.cpp index da5b3de99..6d8b76fe9 100644 --- a/lib/php/src/ext/thrift_protocol/php_thrift_protocol7.cpp +++ b/lib/php/src/ext/thrift_protocol/php_thrift_protocol7.cpp @@ -849,6 +849,44 @@ bool ttypes_are_compatible(int8_t t1, int8_t t2) { return ((t1 == t2) || (ttype_is_int(t1) && ttype_is_int(t2))); } +//is used to validate objects before serialization and after deserialization. For now, only required fields are validated. +static +void validate_thrift_object(zval* object) { + zend_class_entry* object_class_entry = Z_OBJCE_P(object); + zval* is_validate = zend_read_static_property(object_class_entry, "isValidate", sizeof("isValidate")-1, false); + zval* spec = zend_read_static_property(object_class_entry, "_TSPEC", sizeof("_TSPEC")-1, false); + HashPosition key_ptr; + zval* val_ptr; + + if (Z_TYPE_INFO_P(is_validate) == IS_TRUE) { + for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(spec), &key_ptr); + (val_ptr = zend_hash_get_current_data_ex(Z_ARRVAL_P(spec), &key_ptr)) != nullptr; + zend_hash_move_forward_ex(Z_ARRVAL_P(spec), &key_ptr)) { + + zend_ulong fieldno; + if (zend_hash_get_current_key_ex(Z_ARRVAL_P(spec), nullptr, &fieldno, &key_ptr) != HASH_KEY_IS_LONG) { + throw_tprotocolexception("Bad keytype in TSPEC (expected 'long')", INVALID_DATA); + return; + } + HashTable* fieldspec = Z_ARRVAL_P(val_ptr); + + // field name + zval* zvarname = zend_hash_str_find(fieldspec, "var", sizeof("var")-1); + char* varname = Z_STRVAL_P(zvarname); + + zval* is_required = zend_hash_str_find(fieldspec, "isRequired", sizeof("isRequired")-1); + zval rv; + zval* prop = zend_read_property(object_class_entry, object, varname, strlen(varname), false, &rv); + + if (Z_TYPE_INFO_P(is_required) == IS_TRUE && Z_TYPE_P(prop) == IS_NULL) { + char errbuf[128]; + snprintf(errbuf, 128, "Required field %s.%s is unset!", ZSTR_VAL(object_class_entry->name), varname); + throw_tprotocolexception(errbuf, INVALID_DATA); + } + } + } +} + static void binary_deserialize_spec(zval* zthis, PHPInputTransport& transport, HashTable* spec) { // SET and LIST have 'elem' => array('type', [optional] 'class') @@ -857,6 +895,7 @@ void binary_deserialize_spec(zval* zthis, PHPInputTransport& transport, HashTabl while (true) { int8_t ttype = transport.readI8(); if (ttype == T_STOP) { + validate_thrift_object(zthis); return; } @@ -892,6 +931,9 @@ void binary_deserialize_spec(zval* zthis, PHPInputTransport& transport, HashTabl static void binary_serialize_spec(zval* zthis, PHPOutputTransport& transport, HashTable* spec) { + + validate_thrift_object(zthis); + HashPosition key_ptr; zval* val_ptr; |