2020-08-22 14:04:42 +00:00
|
|
|
|
/*
|
|
|
|
|
+----------------------------------------------------------------------+
|
|
|
|
|
| PHP Version 7 |
|
|
|
|
|
+----------------------------------------------------------------------+
|
|
|
|
|
| Copyright (c) 2020 The PHP Group |
|
|
|
|
|
+----------------------------------------------------------------------+
|
|
|
|
|
| http://www.opensource.org/licenses/mit-license.php MIT License |
|
|
|
|
|
+----------------------------------------------------------------------+
|
|
|
|
|
| Author: Stefan Siegl <stesie@php.net> |
|
|
|
|
|
+----------------------------------------------------------------------+
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
|
#include "config.h"
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#include "php_v8js_macros.h"
|
|
|
|
|
#include "v8js_exceptions.h"
|
|
|
|
|
#include "v8js_v8inspector_class.h"
|
|
|
|
|
|
2020-08-22 14:33:44 +00:00
|
|
|
|
#include <v8-inspector.h>
|
|
|
|
|
|
2020-08-22 14:04:42 +00:00
|
|
|
|
extern "C" {
|
|
|
|
|
#include "zend_exceptions.h"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* {{{ Class Entries */
|
|
|
|
|
zend_class_entry *php_ce_v8inspector;
|
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
|
|
/* {{{ Object Handlers */
|
|
|
|
|
static zend_object_handlers v8js_v8inspector_handlers;
|
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2020-08-22 14:33:44 +00:00
|
|
|
|
class InspectorFrontend final : public v8_inspector::V8Inspector::Channel {
|
|
|
|
|
public:
|
2020-08-22 17:01:55 +00:00
|
|
|
|
explicit InspectorFrontend(v8::Local<v8::Context> context, zval *response_handler, zval *notification_handler) {
|
2020-08-22 14:33:44 +00:00
|
|
|
|
isolate_ = context->GetIsolate();
|
2020-08-22 17:01:55 +00:00
|
|
|
|
response_handler_ = response_handler;
|
|
|
|
|
notification_handler_ = notification_handler;
|
2020-08-22 14:33:44 +00:00
|
|
|
|
}
|
|
|
|
|
~InspectorFrontend() override = default;
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
void sendResponse(
|
|
|
|
|
int callId,
|
|
|
|
|
std::unique_ptr<v8_inspector::StringBuffer> message) override {
|
2020-08-22 17:01:55 +00:00
|
|
|
|
invokeHandler(message->string(), response_handler_);
|
2020-08-22 14:33:44 +00:00
|
|
|
|
}
|
|
|
|
|
void sendNotification(
|
|
|
|
|
std::unique_ptr<v8_inspector::StringBuffer> message) override {
|
2020-08-22 17:01:55 +00:00
|
|
|
|
invokeHandler(message->string(), notification_handler_);
|
2020-08-22 14:33:44 +00:00
|
|
|
|
}
|
|
|
|
|
void flushProtocolNotifications() override {}
|
|
|
|
|
|
|
|
|
|
|
2020-08-22 17:01:55 +00:00
|
|
|
|
void invokeHandler(const v8_inspector::StringView& string, zval *handler) {
|
|
|
|
|
if (Z_TYPE_P(handler) == IS_NULL) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-22 14:33:44 +00:00
|
|
|
|
v8::HandleScope handle_scope(isolate_);
|
|
|
|
|
int length = static_cast<int>(string.length());
|
|
|
|
|
v8::Local<v8::String> message =
|
|
|
|
|
(string.is8Bit()
|
|
|
|
|
? v8::String::NewFromOneByte(
|
|
|
|
|
isolate_,
|
|
|
|
|
reinterpret_cast<const uint8_t*>(string.characters8()),
|
|
|
|
|
v8::NewStringType::kNormal, length)
|
|
|
|
|
: v8::String::NewFromTwoByte(
|
|
|
|
|
isolate_,
|
|
|
|
|
reinterpret_cast<const uint16_t*>(string.characters16()),
|
|
|
|
|
v8::NewStringType::kNormal, length))
|
|
|
|
|
.ToLocalChecked();
|
|
|
|
|
|
|
|
|
|
v8::String::Utf8Value str(isolate_, message);
|
|
|
|
|
const char *cstr = ToCString(str);
|
2020-08-22 17:01:55 +00:00
|
|
|
|
|
|
|
|
|
zval handler_result;
|
|
|
|
|
zval params[1];
|
|
|
|
|
ZVAL_STRINGL(¶ms[0], cstr, str.length());
|
|
|
|
|
call_user_function_ex(EG(function_table), NULL, handler, &handler_result, 1, params, 0, NULL);
|
2020-08-22 14:33:44 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
v8::Isolate* isolate_;
|
2020-08-22 17:01:55 +00:00
|
|
|
|
zval *response_handler_;
|
|
|
|
|
zval *notification_handler_;
|
2020-08-22 14:33:44 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class InspectorClient : public v8_inspector::V8InspectorClient {
|
|
|
|
|
public:
|
2020-08-22 17:01:55 +00:00
|
|
|
|
InspectorClient(v8::Local<v8::Context> context, zval *response_handler, zval *notification_handler) {
|
2020-08-22 14:33:44 +00:00
|
|
|
|
isolate_ = context->GetIsolate();
|
2020-08-22 17:01:55 +00:00
|
|
|
|
channel_.reset(new InspectorFrontend(context, response_handler, notification_handler));
|
2020-08-22 14:33:44 +00:00
|
|
|
|
inspector_ = v8_inspector::V8Inspector::create(isolate_, this);
|
2020-08-22 16:31:39 +00:00
|
|
|
|
session_ = inspector_->connect(1, channel_.get(), v8_inspector::StringView());
|
2020-08-22 14:33:44 +00:00
|
|
|
|
inspector_->contextCreated(v8_inspector::V8ContextInfo(
|
|
|
|
|
context, kContextGroupId, v8_inspector::StringView()));
|
|
|
|
|
context_.Reset(isolate_, context);
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-22 15:03:38 +00:00
|
|
|
|
void send(const zend_string *message) {
|
|
|
|
|
v8::Locker locker(isolate_);
|
|
|
|
|
v8::HandleScope handle_scope(isolate_);
|
|
|
|
|
v8_inspector::StringView message_view((const uint8_t*) ZSTR_VAL(message), ZSTR_LEN(message));
|
|
|
|
|
{
|
|
|
|
|
v8::SealHandleScope seal_handle_scope(isolate_);
|
|
|
|
|
session_->dispatchProtocolMessage(message_view);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-22 14:33:44 +00:00
|
|
|
|
private:
|
|
|
|
|
static const int kContextGroupId = 1;
|
|
|
|
|
|
|
|
|
|
std::unique_ptr<v8_inspector::V8Inspector> inspector_;
|
|
|
|
|
std::unique_ptr<v8_inspector::V8InspectorSession> session_;
|
|
|
|
|
std::unique_ptr<v8_inspector::V8Inspector::Channel> channel_;
|
|
|
|
|
v8::Global<v8::Context> context_;
|
|
|
|
|
v8::Isolate* isolate_;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2020-08-22 14:04:42 +00:00
|
|
|
|
static void v8js_v8inspector_free_storage(zend_object *object) /* {{{ */
|
|
|
|
|
{
|
|
|
|
|
v8js_v8inspector *c = v8js_v8inspector_fetch_object(object);
|
|
|
|
|
|
2020-08-22 14:33:44 +00:00
|
|
|
|
delete c->client;
|
2020-08-22 17:01:55 +00:00
|
|
|
|
zval_ptr_dtor(&c->response_handler);
|
|
|
|
|
zval_ptr_dtor(&c->notification_handler);
|
2020-08-22 14:04:42 +00:00
|
|
|
|
|
|
|
|
|
zend_object_std_dtor(&c->std);
|
|
|
|
|
}
|
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
|
|
static zend_object *v8js_v8inspector_new(zend_class_entry *ce) /* {{{ */
|
|
|
|
|
{
|
|
|
|
|
v8js_v8inspector *c;
|
|
|
|
|
c = (v8js_v8inspector *) ecalloc(1, sizeof(v8js_v8inspector) + zend_object_properties_size(ce));
|
|
|
|
|
|
|
|
|
|
zend_object_std_init(&c->std, ce);
|
|
|
|
|
object_properties_init(&c->std, ce);
|
|
|
|
|
|
|
|
|
|
c->std.handlers = &v8js_v8inspector_handlers;
|
2020-08-22 17:01:55 +00:00
|
|
|
|
|
|
|
|
|
ZVAL_NULL(&c->response_handler);
|
|
|
|
|
ZVAL_NULL(&c->notification_handler);
|
2020-08-22 14:04:42 +00:00
|
|
|
|
|
|
|
|
|
return &c->std;
|
|
|
|
|
}
|
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* {{{ proto V8Inspector::__construct()
|
|
|
|
|
*/
|
|
|
|
|
PHP_METHOD(V8Inspector,__construct)
|
|
|
|
|
{
|
|
|
|
|
zend_throw_exception(php_ce_v8js_exception,
|
|
|
|
|
"Can't directly construct V8Inspector objects!", 0);
|
|
|
|
|
RETURN_FALSE;
|
|
|
|
|
}
|
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
|
|
/* {{{ proto V8Inspector::__sleep()
|
|
|
|
|
*/
|
|
|
|
|
PHP_METHOD(V8Inspector, __sleep)
|
|
|
|
|
{
|
|
|
|
|
zend_throw_exception(php_ce_v8js_exception,
|
|
|
|
|
"You cannot serialize or unserialize V8Inspector instances", 0);
|
|
|
|
|
RETURN_FALSE;
|
|
|
|
|
}
|
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
|
|
/* {{{ proto V8Inspector::__wakeup()
|
|
|
|
|
*/
|
|
|
|
|
PHP_METHOD(V8Inspector, __wakeup)
|
|
|
|
|
{
|
|
|
|
|
zend_throw_exception(php_ce_v8js_exception,
|
|
|
|
|
"You cannot serialize or unserialize V8Inspector instances", 0);
|
|
|
|
|
RETURN_FALSE;
|
|
|
|
|
}
|
|
|
|
|
/* }}} */
|
|
|
|
|
|
2020-08-22 15:03:38 +00:00
|
|
|
|
/* {{{ proto void V8Inspector::send(string message)
|
|
|
|
|
*/
|
|
|
|
|
static PHP_METHOD(V8Inspector, send)
|
|
|
|
|
{
|
|
|
|
|
zend_string *message;
|
|
|
|
|
|
|
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &message) == FAILURE) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
v8js_v8inspector *inspector = Z_V8JS_V8INSPECTOR_OBJ_P(getThis());
|
|
|
|
|
inspector->client->send(message);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
/* }}} */
|
|
|
|
|
|
2020-08-22 17:01:55 +00:00
|
|
|
|
/* {{{ proto void V8Inspector::setResponseHandler(callable)
|
|
|
|
|
*/
|
|
|
|
|
static PHP_METHOD(V8Inspector, setResponseHandler)
|
|
|
|
|
{
|
|
|
|
|
v8js_ctx *c;
|
|
|
|
|
zval *callable;
|
|
|
|
|
|
|
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &callable) == FAILURE) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
v8js_v8inspector *inspector = Z_V8JS_V8INSPECTOR_OBJ_P(getThis());
|
|
|
|
|
ZVAL_COPY(&inspector->response_handler, callable);
|
|
|
|
|
}
|
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
|
|
/* {{{ proto void V8Inspector::setNotificationHandler(callable)
|
|
|
|
|
*/
|
|
|
|
|
static PHP_METHOD(V8Inspector, setNotificationHandler)
|
|
|
|
|
{
|
|
|
|
|
v8js_ctx *c;
|
|
|
|
|
zval *callable;
|
|
|
|
|
|
|
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &callable) == FAILURE) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
v8js_v8inspector *inspector = Z_V8JS_V8INSPECTOR_OBJ_P(getThis());
|
|
|
|
|
ZVAL_COPY(&inspector->notification_handler, callable);
|
|
|
|
|
}
|
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
|
|
|
2020-08-22 14:04:42 +00:00
|
|
|
|
void v8js_v8inspector_create(zval *res, v8js_ctx *ctx) /* {{{ */
|
|
|
|
|
{
|
|
|
|
|
object_init_ex(res, php_ce_v8inspector);
|
2020-08-22 14:33:44 +00:00
|
|
|
|
v8js_v8inspector *inspector = Z_V8JS_V8INSPECTOR_OBJ_P(res);
|
|
|
|
|
|
|
|
|
|
V8JS_CTX_PROLOGUE(ctx);
|
2020-08-22 17:01:55 +00:00
|
|
|
|
inspector->client = new InspectorClient(v8_context,
|
|
|
|
|
&inspector->response_handler, &inspector->notification_handler);
|
2020-08-22 14:33:44 +00:00
|
|
|
|
|
2020-08-22 14:04:42 +00:00
|
|
|
|
}
|
|
|
|
|
/* }}} */
|
|
|
|
|
|
2020-08-22 15:03:38 +00:00
|
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_v8inspector_send, 0, 0, 1)
|
|
|
|
|
ZEND_ARG_INFO(0, message)
|
|
|
|
|
ZEND_END_ARG_INFO()
|
|
|
|
|
|
2020-08-22 17:01:55 +00:00
|
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_v8inspector_set_handler, 0, 0, 1)
|
|
|
|
|
ZEND_ARG_INFO(0, callable)
|
|
|
|
|
ZEND_END_ARG_INFO()
|
|
|
|
|
|
2020-08-22 14:04:42 +00:00
|
|
|
|
static const zend_function_entry v8js_v8inspector_methods[] = { /* {{{ */
|
2020-08-22 17:01:55 +00:00
|
|
|
|
PHP_ME(V8Inspector, __construct, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
|
|
|
|
|
PHP_ME(V8Inspector, __sleep, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
|
|
|
|
|
PHP_ME(V8Inspector, __wakeup, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
|
|
|
|
|
PHP_ME(V8Inspector, send, arginfo_v8inspector_send, ZEND_ACC_PUBLIC)
|
|
|
|
|
PHP_ME(V8Inspector, setResponseHandler, arginfo_v8inspector_set_handler, ZEND_ACC_PUBLIC)
|
|
|
|
|
PHP_ME(V8Inspector, setNotificationHandler, arginfo_v8inspector_set_handler, ZEND_ACC_PUBLIC)
|
2020-08-22 14:04:42 +00:00
|
|
|
|
{NULL, NULL, NULL}
|
|
|
|
|
};
|
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
|
|
PHP_MINIT_FUNCTION(v8js_v8inspector_class) /* {{{ */
|
|
|
|
|
{
|
|
|
|
|
zend_class_entry ce;
|
|
|
|
|
|
|
|
|
|
/* V8Inspector Class */
|
|
|
|
|
INIT_CLASS_ENTRY(ce, "V8Inspector", v8js_v8inspector_methods);
|
|
|
|
|
php_ce_v8inspector = zend_register_internal_class(&ce);
|
|
|
|
|
php_ce_v8inspector->ce_flags |= ZEND_ACC_FINAL;
|
|
|
|
|
php_ce_v8inspector->create_object = v8js_v8inspector_new;
|
|
|
|
|
|
|
|
|
|
/* V8Inspector handlers */
|
|
|
|
|
memcpy(&v8js_v8inspector_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
|
|
|
|
|
v8js_v8inspector_handlers.clone_obj = NULL;
|
|
|
|
|
v8js_v8inspector_handlers.cast_object = NULL;
|
|
|
|
|
v8js_v8inspector_handlers.offset = XtOffsetOf(struct v8js_v8inspector, std);
|
|
|
|
|
v8js_v8inspector_handlers.free_obj = v8js_v8inspector_free_storage;
|
|
|
|
|
|
|
|
|
|
return SUCCESS;
|
|
|
|
|
} /* }}} */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Local variables:
|
|
|
|
|
* tab-width: 4
|
|
|
|
|
* c-basic-offset: 4
|
|
|
|
|
* indent-tabs-mode: t
|
|
|
|
|
* End:
|
|
|
|
|
* vim600: noet sw=4 ts=4 fdm=marker
|
|
|
|
|
* vim<600: noet sw=4 ts=4
|
|
|
|
|
*/
|