mirror of
https://github.com/php/pecl-web_services-yar.git
synced 2026-03-23 23:02:13 +01:00
675 lines
20 KiB
C
675 lines
20 KiB
C
/*
|
|
+----------------------------------------------------------------------+
|
|
| Yar - Light, concurrent RPC framework |
|
|
+----------------------------------------------------------------------+
|
|
| Copyright (c) 1997-2011 The PHP Group |
|
|
+----------------------------------------------------------------------+
|
|
| This source file is subject to version 3.01 of the PHP license, |
|
|
| that is bundled with this package in the file LICENSE, and is |
|
|
| available through the world-wide-web at the following url: |
|
|
| http://www.php.net/license/3_01.txt |
|
|
| If you did not receive a copy of the PHP license and are unable to |
|
|
| obtain it through the world-wide-web, please send a note to |
|
|
| license@php.net so we can mail you a copy immediately. |
|
|
+----------------------------------------------------------------------+
|
|
| Author: Xinchen Hui <laruence@php.net> |
|
|
| Zhenyu Zhang <zhangzhenyu@php.net> |
|
|
+----------------------------------------------------------------------+
|
|
*/
|
|
|
|
/* $Id$ */
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include "php.h"
|
|
#include "SAPI.h"
|
|
#include "php_yar.h"
|
|
#include "yar_exception.h"
|
|
#include "yar_packager.h"
|
|
#include "yar_server.h"
|
|
#include "yar_request.h"
|
|
#include "yar_response.h"
|
|
#include "yar_protocol.h"
|
|
|
|
zend_class_entry *yar_server_ce;
|
|
|
|
/* {{{ ARG_INFO */
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_service___construct, 0, 0, 1)
|
|
ZEND_ARG_INFO(0, obj)
|
|
ZEND_ARG_INFO(0, protocol)
|
|
ZEND_END_ARG_INFO()
|
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_service_set_packager, 0, 0, 1)
|
|
ZEND_ARG_INFO(0, protocol)
|
|
ZEND_END_ARG_INFO()
|
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_service_void, 0, 0, 1)
|
|
ZEND_END_ARG_INFO()
|
|
/* }}} */
|
|
|
|
/* {{{ HTML Markups for service info */
|
|
#define HTML_MARKUP_HEADER \
|
|
"<!DOCTYPE html>\n" \
|
|
"<html>\n" \
|
|
" <head>\n" \
|
|
" <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n" \
|
|
" <title>%s - Yar Server</title>\n"
|
|
|
|
#define HTML_MARKUP_CSS \
|
|
" <style>\n" \
|
|
" body { margin: 0; font:14px/20px Verdana, Arial, sans-serif; color: #333; background: #f8f8f8;}\n" \
|
|
" h1, h2, pre { margin: 0; padding: 0;}\n" \
|
|
" h1 { font:bold 28px Verdana,Arial; background:#99c; padding: 12px 5px; border-bottom: 4px solid #669; box-shadow: 0 1px 4px #bbb; color: #222;}\n" \
|
|
" h2 { font:normal 20px/22px Georgia, Times, \"Times New Roman\", serif; padding: 5px 0 8px; margin: 20px 10px 0; border-bottom: 1px solid #ddd; cursor:pointer;}\n" \
|
|
" p, dd { color: #555; }\n" \
|
|
" .api-info { padding: 10px 0; margin-left: 20px; }\n" \
|
|
" .api-block { margin-left: 40px;}\n" \
|
|
" h2 u { font-size:20px;text-decoration:none;padding:10px; }\n" \
|
|
" </style>\n"
|
|
|
|
#define HTML_MARKUP_SCRIPT \
|
|
" <script>\n" \
|
|
" function _t(elem) {\n" \
|
|
" var block = elem.nextSibling;\n" \
|
|
" var info = elem.getElementsByTagName('u')[0];\n" \
|
|
" while (block) {\n" \
|
|
" if ( block.nodeType == 1 && block.className.indexOf('api-block') > -1 ) {\n" \
|
|
" break;\n" \
|
|
" }\n" \
|
|
" block = block.nextSibling;\n" \
|
|
" }\n" \
|
|
" var isHidden = block.style.display == 'none';\n" \
|
|
" block.style.display = isHidden ? '' : 'none';\n" \
|
|
" info.innerHTML = isHidden ? '+' : '-';\n" \
|
|
" }\n" \
|
|
" </script>\n" \
|
|
" </head>\n" \
|
|
" <body>\n" \
|
|
" <!-- powered by yar-" PHP_YAR_VERSION " -->\n"
|
|
|
|
#define HTML_MARKUP_TITLE \
|
|
" <h1>Yar Server: %s</h1>"
|
|
|
|
#define HTML_MARKUP_ENTRY \
|
|
" <h2 onclick=\"_t(this)\"><u>-</u>%s</h2>\n" \
|
|
" <div class=\"api-block\" style=\"display:none\">\n" \
|
|
" <pre style=\"white-space:pre-line\">%s</pre>\n" \
|
|
" </div>\n"
|
|
|
|
#define HTML_MARKUP_FOOTER \
|
|
"</body>\n" \
|
|
"</html>"
|
|
/* }}} */
|
|
|
|
static char * php_yar_get_function_declaration(zend_function *fptr TSRMLS_DC) /* {{{ */ {
|
|
char *offset, *buf;
|
|
zend_uint length = 1024;
|
|
|
|
#define REALLOC_BUF_IF_EXCEED(buf, offset, length, size) \
|
|
if (offset - buf + size >= length) { \
|
|
length += size + 1; \
|
|
buf = erealloc(buf, length); \
|
|
}
|
|
|
|
if (!(fptr->common.fn_flags & ZEND_ACC_PUBLIC)) {
|
|
return NULL;
|
|
}
|
|
|
|
offset = buf = (char *)emalloc(length * sizeof(char));
|
|
|
|
#if PHP_API_VERSION > 20090626
|
|
if (fptr->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) {
|
|
*(offset++) = '&';
|
|
*(offset++) = ' ';
|
|
}
|
|
#endif
|
|
|
|
if (fptr->common.scope) {
|
|
memcpy(offset, fptr->common.scope->name, fptr->common.scope->name_length);
|
|
offset += fptr->common.scope->name_length;
|
|
*(offset++) = ':';
|
|
*(offset++) = ':';
|
|
}
|
|
|
|
{
|
|
size_t name_len = strlen(fptr->common.function_name);
|
|
REALLOC_BUF_IF_EXCEED(buf, offset, length, name_len);
|
|
memcpy(offset, fptr->common.function_name, name_len);
|
|
offset += name_len;
|
|
}
|
|
|
|
*(offset++) = '(';
|
|
if (fptr->common.arg_info) {
|
|
zend_uint i, required;
|
|
zend_arg_info *arg_info = fptr->common.arg_info;
|
|
|
|
required = fptr->common.required_num_args;
|
|
for (i = 0; i < fptr->common.num_args;) {
|
|
if (arg_info->class_name) {
|
|
const char *class_name;
|
|
zend_uint class_name_len;
|
|
if (!strcasecmp(arg_info->class_name, "self") && fptr->common.scope ) {
|
|
class_name = fptr->common.scope->name;
|
|
class_name_len = fptr->common.scope->name_length;
|
|
} else if (!strcasecmp(arg_info->class_name, "parent") && fptr->common.scope->parent) {
|
|
class_name = fptr->common.scope->parent->name;
|
|
class_name_len = fptr->common.scope->parent->name_length;
|
|
} else {
|
|
class_name = arg_info->class_name;
|
|
class_name_len = arg_info->class_name_len;
|
|
}
|
|
REALLOC_BUF_IF_EXCEED(buf, offset, length, class_name_len);
|
|
memcpy(offset, class_name, class_name_len);
|
|
offset += class_name_len;
|
|
*(offset++) = ' ';
|
|
#if PHP_API_VERSION > 20090626
|
|
} else if (arg_info->type_hint) {
|
|
zend_uint type_name_len;
|
|
char *type_name = zend_get_type_by_const(arg_info->type_hint);
|
|
type_name_len = strlen(type_name);
|
|
REALLOC_BUF_IF_EXCEED(buf, offset, length, type_name_len);
|
|
memcpy(offset, type_name, type_name_len);
|
|
offset += type_name_len;
|
|
*(offset++) = ' ';
|
|
#else
|
|
} else if (arg_info->array_type_hint) {
|
|
REALLOC_BUF_IF_EXCEED(buf, offset, length, 5);
|
|
memcpy(offset, "array", 5);
|
|
offset += 5;
|
|
*(offset++) = ' ';
|
|
#endif
|
|
}
|
|
|
|
if (arg_info->pass_by_reference) {
|
|
*(offset++) = '&';
|
|
}
|
|
*(offset++) = '$';
|
|
|
|
if (arg_info->name) {
|
|
REALLOC_BUF_IF_EXCEED(buf, offset, length, arg_info->name_len);
|
|
memcpy(offset, arg_info->name, arg_info->name_len);
|
|
offset += arg_info->name_len;
|
|
} else {
|
|
zend_uint idx = i;
|
|
memcpy(offset, "param", 5);
|
|
offset += 5;
|
|
do {
|
|
*(offset++) = (char) (idx % 10) + '0';
|
|
idx /= 10;
|
|
} while (idx > 0);
|
|
}
|
|
if (i >= required) {
|
|
*(offset++) = ' ';
|
|
*(offset++) = '=';
|
|
*(offset++) = ' ';
|
|
if (fptr->type == ZEND_USER_FUNCTION) {
|
|
zend_op *precv = NULL;
|
|
{
|
|
zend_uint idx = i;
|
|
zend_op *op = ((zend_op_array *)fptr)->opcodes;
|
|
zend_op *end = op + ((zend_op_array *)fptr)->last;
|
|
|
|
++idx;
|
|
while (op < end) {
|
|
if ((op->opcode == ZEND_RECV || op->opcode == ZEND_RECV_INIT)
|
|
#if ((PHP_MAJOR_VERSION == 5) && (PHP_MINOR_VERSION < 4))
|
|
&& op->op1.u.constant.value.lval == (long)idx
|
|
#else
|
|
&& op->op1.num == (long)idx
|
|
#endif
|
|
) {
|
|
precv = op;
|
|
}
|
|
++op;
|
|
}
|
|
}
|
|
if (precv && precv->opcode == ZEND_RECV_INIT
|
|
#if ((PHP_MAJOR_VERSION == 5) && (PHP_MINOR_VERSION < 4))
|
|
&& precv->op2.op_type != IS_UNUSED
|
|
#else
|
|
&& precv->op2_type != IS_UNUSED
|
|
#endif
|
|
) {
|
|
zval *zv, zv_copy;
|
|
int use_copy;
|
|
ALLOC_ZVAL(zv);
|
|
#if ((PHP_MAJOR_VERSION == 5) && (PHP_MINOR_VERSION < 4))
|
|
*zv = precv->op2.u.constant;
|
|
#else
|
|
*zv = *precv->op2.zv;
|
|
#endif
|
|
zval_copy_ctor(zv);
|
|
INIT_PZVAL(zv);
|
|
zval_update_constant_ex(&zv, (void*)1, fptr->common.scope TSRMLS_CC);
|
|
if (Z_TYPE_P(zv) == IS_BOOL) {
|
|
if (Z_LVAL_P(zv)) {
|
|
memcpy(offset, "true", 4);
|
|
offset += 4;
|
|
} else {
|
|
memcpy(offset, "false", 5);
|
|
offset += 5;
|
|
}
|
|
} else if (Z_TYPE_P(zv) == IS_NULL) {
|
|
memcpy(offset, "NULL", 4);
|
|
offset += 4;
|
|
} else if (Z_TYPE_P(zv) == IS_STRING) {
|
|
*(offset++) = '\'';
|
|
REALLOC_BUF_IF_EXCEED(buf, offset, length, MIN(Z_STRLEN_P(zv), 10));
|
|
memcpy(offset, Z_STRVAL_P(zv), MIN(Z_STRLEN_P(zv), 10));
|
|
offset += MIN(Z_STRLEN_P(zv), 10);
|
|
if (Z_STRLEN_P(zv) > 10) {
|
|
*(offset++) = '.';
|
|
*(offset++) = '.';
|
|
*(offset++) = '.';
|
|
}
|
|
*(offset++) = '\'';
|
|
} else if (Z_TYPE_P(zv) == IS_ARRAY) {
|
|
memcpy(offset, "Array", 5);
|
|
offset += 5;
|
|
} else {
|
|
zend_make_printable_zval(zv, &zv_copy, &use_copy);
|
|
REALLOC_BUF_IF_EXCEED(buf, offset, length, Z_STRLEN(zv_copy));
|
|
memcpy(offset, Z_STRVAL(zv_copy), Z_STRLEN(zv_copy));
|
|
offset += Z_STRLEN(zv_copy);
|
|
if (use_copy) {
|
|
zval_dtor(&zv_copy);
|
|
}
|
|
}
|
|
zval_ptr_dtor(&zv);
|
|
}
|
|
} else {
|
|
memcpy(offset, "NULL", 4);
|
|
offset += 4;
|
|
}
|
|
}
|
|
|
|
if (++i < fptr->common.num_args) {
|
|
*(offset++) = ',';
|
|
*(offset++) = ' ';
|
|
}
|
|
arg_info++;
|
|
REALLOC_BUF_IF_EXCEED(buf, offset, length, 32);
|
|
}
|
|
}
|
|
*(offset++) = ')';
|
|
*offset = '\0';
|
|
|
|
return buf;
|
|
}
|
|
/* }}} */
|
|
|
|
static int php_yar_print_info(void *ptr, void *argument TSRMLS_DC) /* {{{ */ {
|
|
zend_function *f = ptr;
|
|
zend_class_entry *ce = argument;
|
|
|
|
if (f->common.fn_flags & ZEND_ACC_PUBLIC
|
|
&& f->common.function_name && *(f->common.function_name) != '_') {
|
|
char *prototype = NULL;
|
|
if ((prototype = php_yar_get_function_declaration(f TSRMLS_CC))) {
|
|
char *buf, *doc_comment = NULL;
|
|
uint buf_len;
|
|
if (f->type == ZEND_USER_FUNCTION) {
|
|
doc_comment = (char *)f->op_array.doc_comment;
|
|
}
|
|
buf_len = spprintf(&buf, 0, HTML_MARKUP_ENTRY, prototype, doc_comment? doc_comment : "");
|
|
efree(prototype);
|
|
PHPWRITE(buf, strlen(buf));
|
|
efree(buf);
|
|
}
|
|
}
|
|
|
|
return ZEND_HASH_APPLY_KEEP;
|
|
} /* }}} */
|
|
|
|
static void php_yar_server_response_header(size_t content_lenth, void *packager_info TSRMLS_DC) /* {{{ */ {
|
|
sapi_header_line ctr = {0};
|
|
char header_line[512];
|
|
|
|
ctr.line_len = snprintf(header_line, sizeof(header_line), "Content-Length: %ld", content_lenth);
|
|
ctr.line = header_line;
|
|
sapi_header_op(SAPI_HEADER_REPLACE, &ctr TSRMLS_CC);
|
|
|
|
ctr.line_len = snprintf(header_line, sizeof(header_line), "Content-Type: text/plain");
|
|
ctr.line = header_line;
|
|
sapi_header_op(SAPI_HEADER_REPLACE, &ctr TSRMLS_CC);
|
|
|
|
ctr.line_len = snprintf(header_line, sizeof(header_line), "Cache-Control: no-cache");
|
|
ctr.line = header_line;
|
|
sapi_header_op(SAPI_HEADER_REPLACE, &ctr TSRMLS_CC);
|
|
|
|
ctr.line_len = snprintf(header_line, sizeof(header_line), "Connection: close");
|
|
ctr.line = header_line;
|
|
sapi_header_op(SAPI_HEADER_REPLACE, &ctr TSRMLS_CC);
|
|
|
|
php_header(TSRMLS_C);
|
|
|
|
return;
|
|
} /* }}} */
|
|
|
|
static void php_yar_server_response(yar_request_t *request, yar_response_t *response TSRMLS_DC) /* {{{ */ {
|
|
zval ret, *tmp;
|
|
char *payload, *err_msg;
|
|
size_t payload_len;
|
|
yar_header_t header = {0};
|
|
|
|
INIT_ZVAL(ret);
|
|
array_init(&ret);
|
|
|
|
add_assoc_long_ex(&ret, ZEND_STRS("i"), response->id);
|
|
add_assoc_long_ex(&ret, ZEND_STRS("s"), response->status);
|
|
if (response->out) {
|
|
add_assoc_string_ex(&ret, ZEND_STRS("o"), response->out, 1);
|
|
}
|
|
if (response->retval) {
|
|
Z_ADDREF_P(response->retval);
|
|
add_assoc_zval_ex(&ret, ZEND_STRS("r"), response->retval);
|
|
}
|
|
if (response->err) {
|
|
Z_ADDREF_P(response->err);
|
|
add_assoc_zval_ex(&ret, ZEND_STRS("e"), response->err);
|
|
}
|
|
|
|
if (!(payload_len = php_yar_packager_pack(NULL, &ret, &payload, &err_msg TSRMLS_CC))) {
|
|
zval_dtor(&ret);
|
|
php_yar_error(response, YAR_ERR_PACKAGER TSRMLS_CC, "%s", err_msg);
|
|
efree(err_msg);
|
|
return;
|
|
}
|
|
zval_dtor(&ret);
|
|
|
|
php_yar_protocol_render(&header, request->id, "PHP Yar Server", NULL, payload_len, 0 TSRMLS_CC);
|
|
if (YAR_G(debug)) {
|
|
php_yar_debug_server("%ld: server response: packager '%s', len '%ld', content '%s'",
|
|
request->id, payload, payload_len - 8, payload + 8);
|
|
}
|
|
|
|
php_yar_server_response_header(sizeof(yar_header_t) + payload_len, payload TSRMLS_CC);
|
|
PHPWRITE((char *)&header, sizeof(yar_header_t));
|
|
if (payload_len) {
|
|
PHPWRITE(payload, payload_len);
|
|
efree(payload);
|
|
return;
|
|
}
|
|
|
|
return;
|
|
} /* }}} */
|
|
|
|
static void php_yar_server_handle(zval *obj TSRMLS_DC) /* {{{ */ {
|
|
char *payload, *err_msg, method[256];
|
|
size_t payload_len;
|
|
zend_bool bailout = 0;
|
|
zval *post_data = NULL, output;
|
|
zend_class_entry *ce;
|
|
yar_response_t *response;
|
|
yar_request_t *request = NULL;
|
|
yar_header_t *header;
|
|
|
|
response = php_yar_response_instance(TSRMLS_C);
|
|
if (!SG(request_info).raw_post_data) {
|
|
goto response_no_output;
|
|
}
|
|
|
|
payload = SG(request_info).raw_post_data;
|
|
payload_len = SG(request_info).raw_post_data_length;
|
|
if (!(header = php_yar_protocol_parse(&payload, &payload_len, &err_msg TSRMLS_CC))) {
|
|
php_yar_error(response, YAR_ERR_PACKAGER TSRMLS_CC, err_msg);
|
|
if (YAR_G(debug)) {
|
|
php_yar_debug_server("0: an malformed request '%s'", payload);
|
|
}
|
|
efree(err_msg);
|
|
goto response_no_output;
|
|
}
|
|
|
|
if (YAR_G(debug)) {
|
|
php_yar_debug_server("%ld: accpect rpc request form '%s'",
|
|
header->id, header->provider? (char *)header->provider : "Yar PHP " PHP_YAR_VERSION);
|
|
}
|
|
|
|
if (!(post_data = php_yar_packager_unpack(payload, payload_len, &err_msg TSRMLS_CC))) {
|
|
php_yar_error(response, YAR_ERR_PACKAGER TSRMLS_CC, err_msg);
|
|
efree(err_msg);
|
|
goto response_no_output;
|
|
}
|
|
|
|
request = php_yar_request_instance(post_data TSRMLS_CC);
|
|
zval_ptr_dtor(&post_data);
|
|
ce = Z_OBJCE_P(obj);
|
|
|
|
if (!php_yar_request_valid(request, response TSRMLS_CC)) {
|
|
goto response_no_output;
|
|
}
|
|
|
|
#if ((PHP_MAJOR_VERSION == 5) && (PHP_MINOR_VERSION < 4))
|
|
if (php_start_ob_buffer(NULL, 0, 0 TSRMLS_CC) != SUCCESS) {
|
|
#else
|
|
if (php_output_start_user(NULL, 0, PHP_OUTPUT_HANDLER_STDFLAGS TSRMLS_CC) == FAILURE) {
|
|
#endif
|
|
php_yar_error(response, YAR_ERR_OUTPUT TSRMLS_CC, "start output buffer failed");
|
|
goto response_no_output;
|
|
}
|
|
|
|
ce = Z_OBJCE_P(obj);
|
|
zend_str_tolower_copy(method, Z_STRVAL_P(request->method), sizeof(method) - 1);
|
|
if (!zend_hash_exists(&ce->function_table, method, strlen(method) + 1)) {
|
|
php_yar_error(response, YAR_ERR_REQUEST TSRMLS_CC, "call to undefined api %s::%s()", ce->name, Z_STRVAL_P(request->method));
|
|
goto response;
|
|
}
|
|
|
|
zend_try {
|
|
uint count;
|
|
zval ***func_params;
|
|
zval *retval_ptr = NULL;
|
|
HashTable *func_params_ht;
|
|
|
|
INIT_ZVAL(output);
|
|
|
|
if (zend_hash_exists(&ce->function_table, ZEND_STRS("__auth"))) {
|
|
zval *provider, *token, func;
|
|
MAKE_STD_ZVAL(provider);
|
|
MAKE_STD_ZVAL(token);
|
|
if (header->provider) {
|
|
ZVAL_STRING(provider, header->provider, 1);
|
|
} else {
|
|
ZVAL_NULL(provider);
|
|
}
|
|
|
|
if (header->token) {
|
|
ZVAL_STRING(token, header->token, 1);
|
|
} else {
|
|
ZVAL_NULL(token);
|
|
}
|
|
|
|
func_params = emalloc(sizeof(zval **) * 2);
|
|
func_params[0] = &provider;
|
|
func_params[1] = &token;
|
|
|
|
ZVAL_STRINGL(&func, "__auth", sizeof("__auth") - 1, 0);
|
|
if (call_user_function_ex(NULL, &obj, &func, &retval_ptr, 2, func_params, 0, NULL TSRMLS_CC) != SUCCESS) {
|
|
efree(func_params);
|
|
zval_ptr_dtor(&token);
|
|
zval_ptr_dtor(&provider);
|
|
php_yar_error(response, YAR_ERR_REQUEST TSRMLS_CC, "call to api %s::%s() failed", ce->name, Z_STRVAL(func));
|
|
goto response;
|
|
}
|
|
|
|
efree(func_params);
|
|
func_params = NULL;
|
|
zval_ptr_dtor(&token);
|
|
zval_ptr_dtor(&provider);
|
|
|
|
if (retval_ptr) {
|
|
if (Z_TYPE_P(retval_ptr) == IS_BOOL && !Z_BVAL_P(retval_ptr)) {
|
|
zval_ptr_dtor(&retval_ptr);
|
|
php_yar_error(response, YAR_ERR_REQUEST TSRMLS_CC, "%s::__auth() return false", ce->name);
|
|
goto response;
|
|
}
|
|
zval_ptr_dtor(&retval_ptr);
|
|
retval_ptr = NULL;
|
|
}
|
|
}
|
|
|
|
func_params_ht = Z_ARRVAL_P(request->parameters);
|
|
count = zend_hash_num_elements(func_params_ht);
|
|
|
|
if (count) {
|
|
uint i = 0;
|
|
func_params = emalloc(sizeof(zval **) * count);
|
|
|
|
for (zend_hash_internal_pointer_reset(func_params_ht);
|
|
zend_hash_get_current_data(func_params_ht, (void **) &func_params[i++]) == SUCCESS;
|
|
zend_hash_move_forward(func_params_ht)
|
|
);
|
|
} else {
|
|
func_params = NULL;
|
|
}
|
|
|
|
if (call_user_function_ex(NULL, &obj, request->method, &retval_ptr, count, func_params, 0, NULL TSRMLS_CC) != SUCCESS) {
|
|
if (func_params) {
|
|
efree(func_params);
|
|
}
|
|
php_yar_error(response, YAR_ERR_REQUEST TSRMLS_CC, "call to api %s::%s() failed", ce->name, Z_STRVAL_P(request->method));
|
|
goto response;
|
|
}
|
|
|
|
if (func_params) {
|
|
efree(func_params);
|
|
}
|
|
|
|
if (retval_ptr) {
|
|
php_yar_response_set_retval(response, retval_ptr TSRMLS_CC);
|
|
}
|
|
} zend_catch {
|
|
bailout = 1;
|
|
} zend_end_try();
|
|
|
|
if (EG(exception)) {
|
|
php_yar_response_set_exception(response, EG(exception) TSRMLS_CC);
|
|
EG(exception) = NULL;
|
|
}
|
|
|
|
response:
|
|
#if ((PHP_MAJOR_VERSION == 5) && (PHP_MINOR_VERSION < 4))
|
|
php_ob_get_buffer(&output TSRMLS_CC);
|
|
php_end_ob_buffer(0, 0 TSRMLS_CC);
|
|
#else
|
|
if (php_output_get_contents(&output TSRMLS_CC) == FAILURE) {
|
|
php_output_end(TSRMLS_C);
|
|
php_yar_error(response, YAR_ERR_OUTPUT TSRMLS_CC, "unable to get ob content");
|
|
goto response_no_output;
|
|
}
|
|
|
|
php_output_discard(TSRMLS_C);
|
|
#endif
|
|
php_yar_response_alter_body(response, Z_STRVAL(output), Z_STRLEN(output), YAR_RESPONSE_REPLACE TSRMLS_CC);
|
|
|
|
response_no_output:
|
|
php_yar_server_response(request, response TSRMLS_CC);
|
|
php_yar_request_dtor(request TSRMLS_CC);
|
|
php_yar_response_dtor(response TSRMLS_CC);
|
|
|
|
if (bailout) {
|
|
zend_bailout();
|
|
}
|
|
|
|
return;
|
|
} /* }}} */
|
|
|
|
static void php_yar_server_info(zval *obj TSRMLS_DC) /* {{{ */ {
|
|
char buf[1024];
|
|
zend_class_entry *ce = Z_OBJCE_P(obj);
|
|
|
|
snprintf(buf, sizeof(buf), HTML_MARKUP_HEADER, ce->name);
|
|
PHPWRITE(buf, strlen(buf));
|
|
|
|
PHPWRITE(HTML_MARKUP_CSS, sizeof(HTML_MARKUP_CSS) - 1);
|
|
PHPWRITE(HTML_MARKUP_SCRIPT, sizeof(HTML_MARKUP_SCRIPT) - 1);
|
|
|
|
snprintf(buf, sizeof(buf), HTML_MARKUP_TITLE, ce->name);
|
|
PHPWRITE(buf, strlen(buf));
|
|
|
|
zend_hash_apply_with_argument(&ce->function_table, (apply_func_arg_t)php_yar_print_info, (void *)(ce) TSRMLS_CC);
|
|
|
|
PHPWRITE(HTML_MARKUP_FOOTER, sizeof(HTML_MARKUP_FOOTER) - 1);
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto Yar_Server::__construct($obj, $protocol = NULL)
|
|
initizing an Yar_Server object */
|
|
PHP_METHOD(yar_server, __construct) {
|
|
zval *obj;
|
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &obj) == FAILURE) {
|
|
return;
|
|
}
|
|
|
|
zend_update_property(yar_server_ce, getThis(), "_executor", sizeof("_executor")-1, obj TSRMLS_CC);
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto Yar_Server::handle()
|
|
start service */
|
|
PHP_METHOD(yar_server, handle)
|
|
{
|
|
char *buf;
|
|
int buf_len;
|
|
|
|
if (SG(headers_sent)) {
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "headers already has been sent");
|
|
RETURN_FALSE;
|
|
} else {
|
|
const char *method;
|
|
zval *executor = NULL;
|
|
|
|
executor = zend_read_property(yar_server_ce, getThis(), ZEND_STRL("_executor"), 0 TSRMLS_CC);
|
|
if (!executor || IS_OBJECT != Z_TYPE_P(executor)) {
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "executor is not a valid object");
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
method = SG(request_info).request_method;
|
|
if (!method || strncasecmp(method, "POST", 4)) {
|
|
php_yar_server_info(executor TSRMLS_CC);
|
|
RETURN_TRUE;
|
|
}
|
|
|
|
php_yar_server_handle(executor TSRMLS_CC);
|
|
}
|
|
|
|
RETURN_TRUE;
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ yar_server_methods */
|
|
zend_function_entry yar_server_methods[] = {
|
|
PHP_ME(yar_server, __construct, arginfo_service___construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR|ZEND_ACC_FINAL)
|
|
PHP_ME(yar_server, handle, arginfo_service_void, ZEND_ACC_PUBLIC)
|
|
PHP_FE_END
|
|
};
|
|
/* }}} */
|
|
|
|
YAR_STARTUP_FUNCTION(service) /* {{{ */ {
|
|
zend_class_entry ce;
|
|
|
|
INIT_CLASS_ENTRY(ce, "Yar_Server", yar_server_methods);
|
|
yar_server_ce = zend_register_internal_class(&ce TSRMLS_CC);
|
|
zend_declare_property_null(yar_server_ce, ZEND_STRL("_executor"), ZEND_ACC_PROTECTED TSRMLS_CC);
|
|
|
|
return SUCCESS;
|
|
}
|
|
/* }}} */
|
|
|
|
YAR_SHUTDOWN_FUNCTION(service) /* {{{ */ {
|
|
return SUCCESS;
|
|
} /* }}} */
|
|
|
|
/*
|
|
* Local variables:
|
|
* tab-width: 4
|
|
* c-basic-offset: 4
|
|
* End:
|
|
* vim600: noet sw=4 ts=4 fdm=marker
|
|
* vim<600: noet sw=4 ts=4
|
|
*/
|