/*
*
* Copyright 2015 gRPC authors.
*
* 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
*
* 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.
*
*/
#include "call_credentials.h"
#include <ext/spl/spl_exceptions.h>
#include <zend_exceptions.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include "call.h"
zend_class_entry *grpc_ce_call_credentials;
PHP_GRPC_DECLARE_OBJECT_HANDLER(call_credentials_ce_handlers)
/* Frees and destroys an instance of wrapped_grpc_call_credentials */
PHP_GRPC_FREE_WRAPPED_FUNC_START(wrapped_grpc_call_credentials)
if (p->wrapped != NULL) {
grpc_call_credentials_release(p->wrapped);
}
PHP_GRPC_FREE_WRAPPED_FUNC_END()
/* Initializes an instance of wrapped_grpc_call_credentials to be
* associated with an object of a class specified by class_type */
php_grpc_zend_object create_wrapped_grpc_call_credentials(
zend_class_entry *class_type TSRMLS_DC) {
PHP_GRPC_ALLOC_CLASS_OBJECT(wrapped_grpc_call_credentials);
zend_object_std_init(&intern->std, class_type TSRMLS_CC);
object_properties_init(&intern->std, class_type);
PHP_GRPC_FREE_CLASS_OBJECT(wrapped_grpc_call_credentials,
call_credentials_ce_handlers);
}
zval *grpc_php_wrap_call_credentials(grpc_call_credentials
*wrapped TSRMLS_DC) {
zval *credentials_object;
PHP_GRPC_MAKE_STD_ZVAL(credentials_object);
object_init_ex(credentials_object, grpc_ce_call_credentials);
wrapped_grpc_call_credentials *credentials =
PHP_GRPC_GET_WRAPPED_OBJECT(wrapped_grpc_call_credentials,
credentials_object);
credentials->wrapped = wrapped;
return credentials_object;
}
/**
* Create composite credentials from two existing credentials.
* @param CallCredentials $cred1_obj The first credential
* @param CallCredentials $cred2_obj The second credential
* @return CallCredentials The new composite credentials object
*/
PHP_METHOD(CallCredentials, createComposite) {
zval *cred1_obj;
zval *cred2_obj;
/* "OO" == 2 Objects */
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "OO", &cred1_obj,
grpc_ce_call_credentials, &cred2_obj,
grpc_ce_call_credentials) == FAILURE) {
zend_throw_exception(spl_ce_InvalidArgumentException,
"createComposite expects 2 CallCredentials",
1 TSRMLS_CC);
return;
}
wrapped_grpc_call_credentials *cred1 =
PHP_GRPC_GET_WRAPPED_OBJECT(wrapped_grpc_call_credentials, cred1_obj);
wrapped_grpc_call_credentials *cred2 =
PHP_GRPC_GET_WRAPPED_OBJECT(wrapped_grpc_call_credentials, cred2_obj);
grpc_call_credentials *creds =
grpc_composite_call_credentials_create(cred1->wrapped, cred2->wrapped,
NULL);
zval *creds_object = grpc_php_wrap_call_credentials(creds TSRMLS_CC);
RETURN_DESTROY_ZVAL(creds_object);
}
/**
* Create a call credentials object from the plugin API
* @param function $fci The callback function
* @return CallCredentials The new call credentials object
*/
PHP_METHOD(CallCredentials, createFromPlugin) {
zend_fcall_info *fci;
zend_fcall_info_cache *fci_cache;
fci = (zend_fcall_info *)malloc(sizeof(zend_fcall_info));
fci_cache = (zend_fcall_info_cache *)malloc(sizeof(zend_fcall_info_cache));
memset(fci, 0, sizeof(zend_fcall_info));
memset(fci_cache, 0, sizeof(zend_fcall_info_cache));
/* "f" == 1 function */
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "f*", fci, fci_cache,
fci->params, fci->param_count) == FAILURE) {
zend_throw_exception(spl_ce_InvalidArgumentException,
"createFromPlugin expects 1 callback", 1 TSRMLS_CC);
free(fci);
free(fci_cache);
return;
}
plugin_state *state;
state = (plugin_state *)malloc(sizeof(plugin_state));
memset(state, 0, sizeof(plugin_state));
/* save the user provided PHP callback function */
state->fci = fci;
state->fci_cache = fci_cache;
grpc_metadata_credentials_plugin plugin;
plugin.get_metadata = plugin_get_metadata;
plugin.destroy = plugin_destroy_state;
plugin.state = (void *)state;
plugin.type = "";
grpc_call_credentials *creds =
grpc_metadata_credentials_create_from_plugin(plugin, NULL);
zval *creds_object = grpc_php_wrap_call_credentials(creds TSRMLS_CC);
RETURN_DESTROY_ZVAL(creds_object);
}
/* Callback function for plugin creds API */
int plugin_get_metadata(
void *ptr, grpc_auth_metadata_context context,
grpc_credentials_plugin_metadata_cb cb, void *user_data,
grpc_metadata creds_md[GRPC_METADATA_CREDENTIALS_PLUGIN_SYNC_MAX],
size_t *num_creds_md, grpc_status_code *status,
const char **error_details) {
TSRMLS_FETCH();
plugin_state *state = (plugin_state *)ptr;
/* prepare to call the user callback function with info from the
* grpc_auth_metadata_context */
zval *arg;
PHP_GRPC_MAKE_STD_ZVAL(arg);
object_init(arg);
php_grpc_add_property_string(arg, "service_url", context.service_url, true);
php_grpc_add_property_string(arg, "method_name", context.method_name, true);
zval *retval = NULL;
#if PHP_MAJOR_VERSION < 7
zval **params[1];
params[0] = &arg;
state->fci->params = params;
state->fci->retval_ptr_ptr = &retval;
#else
PHP_GRPC_MAKE_STD_ZVAL(retval);
state->fci->params = arg;
state->fci->retval = retval;
#endif
state->fci->param_count = 1;
PHP_GRPC_DELREF(arg);
gpr_log(GPR_INFO, "GRPC_PHP: call credentials plugin function - begin");
/* call the user callback function */
zend_call_function(state->fci, state->fci_cache TSRMLS_CC);
gpr_log(GPR_INFO, "GRPC_PHP: call credentials plugin function - end");
*num_creds_md = 0;
*status = GRPC_STATUS_OK;
*error_details = NULL;
bool should_return = false;
grpc_metadata_array metadata;
if (retval == NULL || Z_TYPE_P(retval) != IS_ARRAY) {
*status = GRPC_STATUS_INVALID_ARGUMENT;
should_return = true; // Synchronous return.
}
if (!create_metadata_array(retval, &metadata)) {
*status = GRPC_STATUS_INVALID_ARGUMENT;
should_return = true; // Synchronous return.
grpc_php_metadata_array_destroy_including_entries(&metadata);
}
if (retval != NULL) {
#if PHP_MAJOR_VERSION < 7
zval_ptr_dtor(&retval);
#else
zval_ptr_dtor(arg);
zval_ptr_dtor(retval);
PHP_GRPC_FREE_STD_ZVAL(arg);
PHP_GRPC_FREE_STD_ZVAL(retval);
#endif
}
if (should_return) {
return true;
}
if (metadata.count > GRPC_METADATA_CREDENTIALS_PLUGIN_SYNC_MAX) {
*status = GRPC_STATUS_INTERNAL;
*error_details = gpr_strdup(
"PHP plugin credentials returned too many metadata entries");
for (size_t i = 0; i < metadata.count; i++) {
// TODO(stanleycheung): Why don't we need to unref the key here?
grpc_slice_unref(metadata.metadata[i].value);
}
} else {
// Return data to core.
*num_creds_md = metadata.count;
for (size_t i = 0; i < metadata.count; ++i) {
creds_md[i] = metadata.metadata[i];
}
}
grpc_metadata_array_destroy(&metadata);
return true; // Synchronous return.
}
/* Cleanup function for plugin creds API */
void plugin_destroy_state(void *ptr) {
plugin_state *state = (plugin_state *)ptr;
free(state->fci);
free(state->fci_cache);
#if PHP_MAJOR_VERSION < 7
PHP_GRPC_FREE_STD_ZVAL(state->fci->params);
PHP_GRPC_FREE_STD_ZVAL(state->fci->retval);
#endif
free(state);
}
ZEND_BEGIN_ARG_INFO_EX(arginfo_createComposite, 0, 0, 2)
ZEND_ARG_INFO(0, creds1)
ZEND_ARG_INFO(0, creds2)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_createFromPlugin, 0, 0, 1)
ZEND_ARG_INFO(0, callback)
ZEND_END_ARG_INFO()
static zend_function_entry call_credentials_methods[] = {
PHP_ME(CallCredentials, createComposite, arginfo_createComposite,
ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
PHP_ME(CallCredentials, createFromPlugin, arginfo_createFromPlugin,
ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
PHP_FE_END
};
void grpc_init_call_credentials(TSRMLS_D) {
zend_class_entry ce;
INIT_CLASS_ENTRY(ce, "Grpc\\CallCredentials", call_credentials_methods);
ce.create_object = create_wrapped_grpc_call_credentials;
grpc_ce_call_credentials = zend_register_internal_class(&ce TSRMLS_CC);
PHP_GRPC_INIT_HANDLER(wrapped_grpc_call_credentials,
call_credentials_ce_handlers);
}