From: Mark Huang Date: Fri, 10 Nov 2006 06:31:50 +0000 (+0000) Subject: support marshalling NULL as X-Git-Tag: pycurl-7_13_1~331 X-Git-Url: http://git.onelab.eu/?p=plcapi.git;a=commitdiff_plain;h=3be4cf02fc55d204b46b9a4386d9943fd5f28b9c support marshalling NULL as --- diff --git a/php/header.php b/php/header.php index bdcc747..955a4e9 100644 --- a/php/header.php +++ b/php/header.php @@ -8,7 +8,7 @@ // Mark Huang // Copyright (C) 2005-2006 The Trustees of Princeton University // -// $Id: header.php,v 1.1 2006/10/25 20:32:44 mlhuang Exp $ +// $Id: header.php,v 1.2 2006/10/27 15:40:20 mlhuang Exp $ // // @@ -105,8 +105,10 @@ class PLCAPI $url .= $this->server . ':' . $this->port . '/' . $this->path; curl_setopt($curl, CURLOPT_URL, $url); - // Marshal the XML-RPC request as a POST variable - $request = xmlrpc_encode_request($method, $args); + // Marshal the XML-RPC request as a POST variable. is an + // extension to the XML-RPC spec that is supported in our custom + // version of xmlrpc.so via the 'allow_null' output_encoding key. + $request = xmlrpc_encode_request($method, $args, array('allow_null' => TRUE)); curl_setopt($curl, CURLOPT_POSTFIELDS, $request); // Construct the HTTP header diff --git a/php/xmlrpc/libxmlrpc/xml_to_xmlrpc.c b/php/xmlrpc/libxmlrpc/xml_to_xmlrpc.c index f411d15..fb69963 100644 --- a/php/xmlrpc/libxmlrpc/xml_to_xmlrpc.c +++ b/php/xmlrpc/libxmlrpc/xml_to_xmlrpc.c @@ -58,6 +58,7 @@ static const char rcsid[] = "#(@) $Id: xml_to_xmlrpc.c,v 1.5 2004/04/27 17:33:59 #define ELEM_METHODNAME "methodName" #define ELEM_METHODRESPONSE "methodResponse" #define ELEM_NAME "name" +#define ELEM_NIL "nil" #define ELEM_PARAM "param" #define ELEM_PARAMS "params" #define ELEM_STRING "string" @@ -210,6 +211,9 @@ xml_element* XMLRPC_to_xml_element_worker(XMLRPC_VALUE current_vector, XMLRPC_VA else { switch (type) { case xmlrpc_empty: /* treat null value as empty string in xmlrpc. */ + case xmlrpc_nil: + elem_val->name = strdup(ELEM_NIL); + break; case xmlrpc_string: elem_val->name = strdup(ELEM_STRING); simplestring_addn(&elem_val->text, XMLRPC_GetValueString(node), XMLRPC_GetValueStringLen(node)); diff --git a/php/xmlrpc/libxmlrpc/xmlrpc.c b/php/xmlrpc/libxmlrpc/xmlrpc.c index 16a3809..67242b8 100644 --- a/php/xmlrpc/libxmlrpc/xmlrpc.c +++ b/php/xmlrpc/libxmlrpc/xmlrpc.c @@ -1109,6 +1109,7 @@ int XMLRPC_AddValueToVector(XMLRPC_VALUE target, XMLRPC_VALUE source) { /* guard against putting value of unknown type into vector */ switch(source->type) { case xmlrpc_empty: + case xmlrpc_nil: case xmlrpc_base64: case xmlrpc_boolean: case xmlrpc_datetime: @@ -2423,6 +2424,8 @@ const char* type_to_str(XMLRPC_VALUE_TYPE type, XMLRPC_VECTOR_TYPE vtype) { return "none"; case xmlrpc_empty: return "empty"; + case xmlrpc_nil: + return "nil"; case xmlrpc_base64: return "base64"; case xmlrpc_boolean: diff --git a/php/xmlrpc/libxmlrpc/xmlrpc.h b/php/xmlrpc/libxmlrpc/xmlrpc.h index dde3d5e..eead11c 100644 --- a/php/xmlrpc/libxmlrpc/xmlrpc.h +++ b/php/xmlrpc/libxmlrpc/xmlrpc.h @@ -69,7 +69,8 @@ extern "C" { */ typedef enum _XMLRPC_VALUE_TYPE { xmlrpc_none, /* not a value */ - xmlrpc_empty, /* empty value, eg NULL */ + xmlrpc_empty, /* empty value */ + xmlrpc_nil, /* null value, eg NULL */ xmlrpc_base64, /* base64 value, eg binary data */ xmlrpc_boolean, /* boolean [0 | 1] */ xmlrpc_datetime, /* datetime [ISO8601 | time_t] */ diff --git a/php/xmlrpc/php_xmlrpc.h b/php/xmlrpc/php_xmlrpc.h index c3cee01..b56f844 100644 --- a/php/xmlrpc/php_xmlrpc.h +++ b/php/xmlrpc/php_xmlrpc.h @@ -94,9 +94,9 @@ PHP_FUNCTION(xmlrpc_server_register_introspection_callback); /* Fill in this structure and use entries in it for thread safety instead of using true globals. */ -typedef struct { - int x; /* fix error in msvc, cannot have empty structs */ -} zend_xmlrpc_globals; +ZEND_BEGIN_MODULE_GLOBALS(xmlrpc) + long allow_null; +ZEND_END_MODULE_GLOBALS(xmlrpc) /* In every function that needs to use variables in zend_xmlrpc_globals, do call XMLRPCLS_FETCH(); after declaring other variables used by @@ -105,6 +105,16 @@ typedef struct { examples in any other php module directory. */ +#ifdef ZTS +#define XMLRPCG(v) TSRMG(xmlrpc_globals_id, zend_xmlrpc_globals *, v) +#define XMLRPCLS_FETCH() zend_xmlrpc_globals *xmlrpc_globals = ts_resource(xmlrpc_globals_id) +#else +#define XMLRPCG(v) (xmlrpc_globals.v) +#define XMLRPCLS_FETCH() +#endif + +ZEND_EXTERN_MODULE_GLOBALS(xmlrpc) + #else #define phpext_xmlrpc_ptr NULL diff --git a/php/xmlrpc/xmlrpc-epi-php.c b/php/xmlrpc/xmlrpc-epi-php.c index befaec8..7e19c7e 100644 --- a/php/xmlrpc/xmlrpc-epi-php.c +++ b/php/xmlrpc/xmlrpc-epi-php.c @@ -118,6 +118,15 @@ ZEND_GET_MODULE(xmlrpc) # endif #endif +PHP_INI_BEGIN() +STD_PHP_INI_BOOLEAN("xmlrpc.allow_null", "0", PHP_INI_ALL, OnUpdateBool, allow_null, zend_xmlrpc_globals, xmlrpc_globals) +PHP_INI_END() + +static void php_xmlrpc_init_globals(zend_xmlrpc_globals *xmlrpc_globals) +{ + memset(xmlrpc_globals, 0, sizeof(zend_xmlrpc_globals)); +} + /******************************* * local structures and defines * *******************************/ @@ -134,6 +143,7 @@ typedef struct _xmlrpc_server_data { typedef struct _php_output_options { int b_php_out; int b_auto_version; + int b_allow_null; STRUCT_XMLRPC_REQUEST_OUTPUT_OPTIONS xmlrpc_out; } php_output_options; @@ -153,6 +163,9 @@ typedef struct _xmlrpc_callback_data { #define OUTPUT_TYPE_VALUE_PHP "php" #define OUTPUT_TYPE_VALUE_XML "xml" +#define ALLOW_NULL_KEY "allow_null" +#define ALLOW_NULL_KEY_LEN (sizeof(ALLOW_NULL_KEY) - 1) + #define VERBOSITY_KEY "verbosity" #define VERBOSITY_KEY_LEN (sizeof(VERBOSITY_KEY) - 1) #define VERBOSITY_VALUE_NO_WHITE_SPACE "no_white_space" @@ -191,7 +204,7 @@ typedef struct _xmlrpc_callback_data { /*********************** * forward declarations * ***********************/ -XMLRPC_VALUE_TYPE get_zval_xmlrpc_type(zval* value, zval** newvalue); +XMLRPC_VALUE_TYPE get_zval_xmlrpc_type(php_output_options* out, zval* value, zval** newvalue); static void php_xmlrpc_introspection_callback(XMLRPC_SERVER server, void* data); int sset_zval_xmlrpc_type(zval* value, XMLRPC_VALUE_TYPE type); zval* decode_request_worker(zval* xml_in, zval* encoding_in, zval* method_name_out); @@ -231,6 +244,10 @@ static void xmlrpc_server_destructor(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* module init */ PHP_MINIT_FUNCTION(xmlrpc) { + ZEND_INIT_MODULE_GLOBALS(xmlrpc, php_xmlrpc_init_globals, NULL); + + REGISTER_INI_ENTRIES(); + le_xmlrpc_server = zend_register_list_destructors_ex(xmlrpc_server_destructor, NULL, "xmlrpc server", module_number); return SUCCESS; @@ -320,11 +337,14 @@ static int add_zval(zval* list, const char* id, zval** val) * and determine whether to return data as xml or php vars */ static void set_output_options(php_output_options* options, zval* output_opts) { + XMLRPCLS_FETCH(); + if (options) { /* defaults */ options->b_php_out = 0; options->b_auto_version = 1; + options->b_allow_null = 0; options->xmlrpc_out.version = xmlrpc_version_1_0; options->xmlrpc_out.xml_elem_opts.encoding = ENCODING_DEFAULT; options->xmlrpc_out.xml_elem_opts.verbosity = xml_elem_pretty; @@ -333,6 +353,17 @@ static void set_output_options(php_output_options* options, zval* output_opts) if (output_opts && Z_TYPE_P(output_opts) == IS_ARRAY) { zval** val; + /* marshal NULL */ + if (zend_hash_find(Z_ARRVAL_P(output_opts), ALLOW_NULL_KEY, ALLOW_NULL_KEY_LEN + 1, (void**) &val) == SUCCESS) { + if (Z_TYPE_PP(val) == IS_BOOL) { + if (Z_LVAL_PP(val)) { + options->b_allow_null = 1; + } else { + options->b_allow_null = 0; + } + } + } + /* type of output (xml/php) */ if (zend_hash_find(Z_ARRVAL_P(output_opts), OUTPUT_TYPE_KEY, OUTPUT_TYPE_KEY_LEN + 1, (void**) &val) == SUCCESS) { if (Z_TYPE_PP(val) == IS_STRING) { @@ -478,22 +509,20 @@ static XMLRPC_VECTOR_TYPE determine_vector_type (HashTable *ht) } /* recursively convert php values into xmlrpc values */ -static XMLRPC_VALUE PHP_to_XMLRPC_worker (const char* key, zval* in_val, int depth) +static XMLRPC_VALUE PHP_to_XMLRPC_worker (php_output_options* out, const char* key, zval* in_val, int depth) { XMLRPC_VALUE xReturn = NULL; if(in_val) { zval* val = NULL; - XMLRPC_VALUE_TYPE type = get_zval_xmlrpc_type(in_val, &val); + XMLRPC_VALUE_TYPE type = get_zval_xmlrpc_type(out, in_val, &val); if(val) { switch(type) { + case xmlrpc_nil: + xReturn = XMLRPC_CreateValueEmpty(); + XMLRPC_SetValueID(xReturn, key, 0); + break; case xmlrpc_base64: - if(Z_TYPE_P(val) == IS_NULL) { - xReturn = XMLRPC_CreateValueEmpty(); - XMLRPC_SetValueID(xReturn, key, 0); - } - else { - xReturn = XMLRPC_CreateValueBase64(key, Z_STRVAL_P(val), Z_STRLEN_P(val)); - } + xReturn = XMLRPC_CreateValueBase64(key, Z_STRVAL_P(val), Z_STRLEN_P(val)); break; case xmlrpc_datetime: convert_to_string(val); @@ -530,7 +559,7 @@ static XMLRPC_VALUE PHP_to_XMLRPC_worker (const char* key, zval* in_val, int dep int res = my_zend_hash_get_current_key(Z_ARRVAL_P(val), &my_key, &num_index); if(res == HASH_KEY_IS_LONG) { if(zend_hash_get_current_data(Z_ARRVAL_P(val), (void**)&pIter) == SUCCESS) { - XMLRPC_AddValueToVector(xReturn, PHP_to_XMLRPC_worker(0, *pIter, depth++)); + XMLRPC_AddValueToVector(xReturn, PHP_to_XMLRPC_worker(out, 0, *pIter, depth++)); } } else if(res == HASH_KEY_NON_EXISTANT) { @@ -538,7 +567,7 @@ static XMLRPC_VALUE PHP_to_XMLRPC_worker (const char* key, zval* in_val, int dep } else if(res == HASH_KEY_IS_STRING) { if(zend_hash_get_current_data(Z_ARRVAL_P(val), (void**)&pIter) == SUCCESS) { - XMLRPC_AddValueToVector(xReturn, PHP_to_XMLRPC_worker(my_key, *pIter, depth++)); + XMLRPC_AddValueToVector(xReturn, PHP_to_XMLRPC_worker(out, my_key, *pIter, depth++)); } } @@ -554,9 +583,9 @@ static XMLRPC_VALUE PHP_to_XMLRPC_worker (const char* key, zval* in_val, int dep return xReturn; } -static XMLRPC_VALUE PHP_to_XMLRPC(zval* root_val) +static XMLRPC_VALUE PHP_to_XMLRPC(php_output_options* out, zval* root_val) { - return PHP_to_XMLRPC_worker(NULL, root_val, 0); + return PHP_to_XMLRPC_worker(out, NULL, root_val, 0); } /* recursively convert xmlrpc values into php values */ @@ -572,6 +601,7 @@ static zval* XMLRPC_to_PHP(XMLRPC_VALUE el) switch(type) { case xmlrpc_empty: + case xmlrpc_nil: Z_TYPE_P(elem) = IS_NULL; break; case xmlrpc_string: @@ -656,7 +686,7 @@ PHP_FUNCTION(xmlrpc_encode_request) XMLRPC_RequestSetRequestType(xRequest, xmlrpc_request_call); } if (Z_TYPE_PP(vals) != IS_NULL) { - XMLRPC_RequestSetData(xRequest, PHP_to_XMLRPC(*vals)); + XMLRPC_RequestSetData(xRequest, PHP_to_XMLRPC(&out, *vals)); } outBuf = XMLRPC_REQUEST_ToXML(xRequest, 0); @@ -684,7 +714,7 @@ PHP_FUNCTION(xmlrpc_encode) if( return_value_used ) { /* convert native php type to xmlrpc type */ - xOut = PHP_to_XMLRPC(*arg1); + xOut = PHP_to_XMLRPC(NULL, *arg1); /* generate raw xml from xmlrpc data */ outBuf = XMLRPC_VALUE_ToXML(xOut, 0); @@ -1086,7 +1116,7 @@ PHP_FUNCTION(xmlrpc_server_call_method) FREE_ZVAL(data.return_data); data.return_data = XMLRPC_to_PHP(xAnswer); } else if(data.php_executed && !out.b_php_out) { - xAnswer = PHP_to_XMLRPC(data.return_data); + xAnswer = PHP_to_XMLRPC(&out, data.return_data); } /* should we return data as xml? */ @@ -1155,7 +1185,7 @@ PHP_FUNCTION(xmlrpc_server_add_introspection_data) server = zend_list_find(Z_LVAL_PP(handle), &type); if (type == le_xmlrpc_server) { - XMLRPC_VALUE xDesc = PHP_to_XMLRPC(*desc); + XMLRPC_VALUE xDesc = PHP_to_XMLRPC(NULL, *desc); if (xDesc) { int retval = XMLRPC_ServerAddIntrospectionData(server->server_ptr, xDesc); XMLRPC_CleanupValue(xDesc); @@ -1211,7 +1241,7 @@ PHP_FUNCTION(xmlrpc_parse_method_descriptions) * type data * ************/ -#define XMLRPC_TYPE_COUNT 9 +#define XMLRPC_TYPE_COUNT 10 #define XMLRPC_VECTOR_TYPE_COUNT 4 #define TYPE_STR_MAP_SIZE (XMLRPC_TYPE_COUNT + XMLRPC_VECTOR_TYPE_COUNT) @@ -1224,6 +1254,7 @@ static const char** get_type_str_mapping(void) /* warning. do not add/delete without changing size define */ str_mapping[xmlrpc_none] = "none"; str_mapping[xmlrpc_empty] = "empty"; + str_mapping[xmlrpc_nil] = "nil"; str_mapping[xmlrpc_base64] = "base64"; str_mapping[xmlrpc_boolean] = "boolean"; str_mapping[xmlrpc_datetime] = "datetime"; @@ -1339,15 +1370,20 @@ int set_zval_xmlrpc_type(zval* value, XMLRPC_VALUE_TYPE newtype) } /* return xmlrpc type of a php value */ -XMLRPC_VALUE_TYPE get_zval_xmlrpc_type(zval* value, zval** newvalue) +XMLRPC_VALUE_TYPE get_zval_xmlrpc_type(php_output_options* out, zval* value, zval** newvalue) { XMLRPC_VALUE_TYPE type = xmlrpc_none; TSRMLS_FETCH(); + XMLRPCLS_FETCH(); if (value) { switch (Z_TYPE_P(value)) { case IS_NULL: - type = xmlrpc_base64; + if (XMLRPCG(allow_null) || (out && out->b_allow_null)) { + type = xmlrpc_nil; + } else { + type = xmlrpc_string; + } break; #ifndef BOOL_AS_LONG @@ -1408,7 +1444,7 @@ XMLRPC_VALUE_TYPE get_zval_xmlrpc_type(zval* value, zval** newvalue) /* {{{ proto bool xmlrpc_set_type(string value, string type) - Sets xmlrpc type, base64 or datetime, for a PHP string value */ + Sets xmlrpc type, base64 or datetime or nil, for a PHP string value */ PHP_FUNCTION(xmlrpc_set_type) { zval **arg, **type; @@ -1443,7 +1479,7 @@ PHP_FUNCTION(xmlrpc_get_type) WRONG_PARAM_COUNT; } - type = get_zval_xmlrpc_type(*arg, 0); + type = get_zval_xmlrpc_type(NULL, *arg, 0); if (type == xmlrpc_vector) { vtype = determine_vector_type(Z_ARRVAL_PP(arg)); }