Fetch `Context` reference from calling `Engine`, not a stored pointer

This fixes compatibility with Go 1.6, which specifies stricter rules for
passing Go pointers to C and vice versa. Exported methods now use the
C context's pointer hexadecimal representation to find the parent Go
Context.
This commit is contained in:
Alex Palaistras 2016-02-21 19:11:50 +00:00
parent 3eaec657a3
commit 7d563c7fe6
4 changed files with 59 additions and 28 deletions

View File

@ -11,7 +11,7 @@
#include "value.h"
#include "context.h"
engine_context *context_new(void *ctx) {
engine_context *context_new() {
engine_context *context;
// Initialize context.
@ -21,7 +21,6 @@ engine_context *context_new(void *ctx) {
return NULL;
}
context->ctx = ctx;
SG(server_context) = context;
// Initialize request lifecycle.

View File

@ -33,7 +33,7 @@ const char engine_ini_defaults[] = {
static ENGINE_UB_WRITE(str, len) {
engine_context *context = SG(server_context);
int written = engineWriteOut(context->ctx, (void *) str, len);
int written = engineWriteOut(context, (void *) str, len);
if (written != len) {
php_handle_aborted_connection();
}
@ -48,7 +48,7 @@ static int engine_header_handler(sapi_header_struct *sapi_header, sapi_header_op
case SAPI_HEADER_REPLACE:
case SAPI_HEADER_ADD:
case SAPI_HEADER_DELETE:
engineSetHeader(context->ctx, op, (void *) sapi_header->header, sapi_header->header_len);
engineSetHeader(context, op, (void *) sapi_header->header, sapi_header->header_len);
break;
}
@ -70,7 +70,7 @@ static void engine_register_variables(zval *track_vars_array) {
static void engine_log_message(char *str) {
engine_context *context = SG(server_context);
engineWriteLog(context->ctx, (void *) str, strlen(str));
engineWriteLog(context, (void *) str, strlen(str));
}
static sapi_module_struct engine_module = {

View File

@ -26,42 +26,50 @@ import (
// Engine represents the core PHP engine bindings.
type Engine struct {
engine *C.struct__php_engine
contexts []*Context
contexts map[string]*Context
}
// This contains a reference to the active engine, if any.
var engine *Engine
// New initializes a PHP engine instance on which contexts can be executed. It
// corresponds to PHP's MINIT (module init) phase.
func New() (*Engine, error) {
if engine != nil {
return nil, fmt.Errorf("Cannot activate multiple engine instances")
}
ptr, err := C.engine_init()
if err != nil {
return nil, fmt.Errorf("PHP engine failed to initialize")
}
e := &Engine{
engine = &Engine{
engine: ptr,
contexts: make([]*Context, 0),
contexts: make(map[string]*Context),
}
return e, nil
return engine, nil
}
// NewContext creates a new execution context for the active engine and returns
// an error if the execution context failed to initialize at any point. This
// corresponds to PHP's RINIT (request init) phase.
func (e *Engine) NewContext() (*Context, error) {
ctx := &Context{
Header: make(http.Header),
values: make([]*Value, 0),
receivers: make(map[string]*Receiver),
}
ptr, err := C.context_new(unsafe.Pointer(ctx))
ptr, err := C.context_new()
if err != nil {
return nil, fmt.Errorf("Failed to initialize context for PHP engine")
}
ctx.context = ptr
e.contexts = append(e.contexts, ctx)
ctx := &Context{
Header: make(http.Header),
context: ptr,
values: make([]*Value, 0),
receivers: make(map[string]*Receiver),
}
// Store reference to context, using pointer as key.
e.contexts[contextPtrKey(ptr)] = ctx
return ctx, nil
}
@ -80,6 +88,22 @@ func (e *Engine) Destroy() {
C.engine_shutdown(e.engine)
e.engine = nil
engine = nil
}
func contextPtrKey(ctxptr interface{}) string {
return fmt.Sprintf("%p", ctxptr)
}
func contextFromPtr(ctxptr unsafe.Pointer) *Context {
key := contextPtrKey(ctxptr)
if engine == nil || engine.contexts[key] == nil {
return nil
}
return engine.contexts[key]
}
func write(w io.Writer, buffer unsafe.Pointer, length C.uint) C.int {
@ -98,21 +122,30 @@ func write(w io.Writer, buffer unsafe.Pointer, length C.uint) C.int {
//export engineWriteOut
func engineWriteOut(ctxptr, buffer unsafe.Pointer, length C.uint) C.int {
c := (*Context)(ctxptr)
ctx := contextFromPtr(ctxptr)
if ctx == nil {
return -1
}
return write(c.Output, buffer, length)
return write(ctx.Output, buffer, length)
}
//export engineWriteLog
func engineWriteLog(ctxptr unsafe.Pointer, buffer unsafe.Pointer, length C.uint) C.int {
c := (*Context)(ctxptr)
ctx := contextFromPtr(ctxptr)
if ctx == nil {
return -1
}
return write(c.Log, buffer, length)
return write(ctx.Log, buffer, length)
}
//export engineSetHeader
func engineSetHeader(ctxptr unsafe.Pointer, operation C.uint, buffer unsafe.Pointer, length C.uint) {
c := (*Context)(ctxptr)
ctx := contextFromPtr(ctxptr)
if ctx == nil {
return
}
header := (string)(C.GoBytes(buffer, C.int(length)))
split := strings.SplitN(header, ":", 2)
@ -124,15 +157,15 @@ func engineSetHeader(ctxptr unsafe.Pointer, operation C.uint, buffer unsafe.Poin
switch operation {
case 0: // Replace header.
if len(split) == 2 && split[1] != "" {
c.Header.Set(split[0], split[1])
ctx.Header.Set(split[0], split[1])
}
case 1: // Append header.
if len(split) == 2 && split[1] != "" {
c.Header.Add(split[0], split[1])
ctx.Header.Add(split[0], split[1])
}
case 2: // Delete header.
if split[0] != "" {
c.Header.Del(split[0])
ctx.Header.Del(split[0])
}
}
}

View File

@ -8,10 +8,9 @@
#include "_context.h"
typedef struct _engine_context {
void *ctx;
} engine_context;
engine_context *context_new(void *ctx);
engine_context *context_new();
void context_exec(engine_context *context, char *filename);
void *context_eval(engine_context *context, char *script);
void context_bind(engine_context *context, char *name, void *value);