Skip to content

Commit 4f22d4e

Browse files
committed
Add "Buffer" type to allow passing PHP output as buffers to Node.
1 parent 14599d9 commit 4f22d4e

File tree

5 files changed

+52
-8
lines changed

5 files changed

+52
-8
lines changed

src/messages.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,9 @@ class JsInvokeMethodMsg : public MessageToJs {
111111
name_.SetOwnedString(name, strlen(name));
112112
}
113113
virtual ~JsInvokeMethodMsg() { delete[] argv_; }
114+
// this is a bit of a hack to allow constructing a call with a Buffer
115+
// as an argument.
116+
Value &Argv(int n) { return argv_[n]; }
114117
protected:
115118
virtual void InJs(ObjectMapper *m) {
116119
Nan::MaybeLocal<v8::Object> o = Nan::To<v8::Object>(obj_.ToJs(m));

src/node_php_embed.cc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -115,12 +115,12 @@ static int node_php_embed_ub_write(const char *str, unsigned int str_length TSRM
115115
(messageChannel->GetWorker());
116116
ZVal stream(ZEND_FILE_LINE_C);
117117
worker->GetStream().ToPhp(messageChannel, stream TSRMLS_CC);
118-
// Creating buf "the hard way" to avoid unnecessary copying of str.
119-
zval buf;
120-
INIT_ZVAL(buf); ZVAL_STRINGL(&buf, str, str_length, 0);
118+
zval buf; INIT_ZVAL(buf); // stack allocate a null zval as a placeholder
121119
zval *args[] = { &buf };
122-
// XXX, would be better to pass this as a buffer, not a string.
123120
JsInvokeMethodMsg msg(messageChannel, stream.Ptr(), "write", 1, args);
121+
// hack the message to pass a buffer, not a string
122+
// (and avoid unnecessary copying by not using an "owned buffer")
123+
msg.Argv(0).SetBuffer(str, str_length);
124124
messageChannel->Send(&msg);
125125
// XXX wait for response
126126
msg.WaitForResponse(); // XXX optional?

src/values.h

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,22 @@ class ZVal : public NonAssignable {
187187
}
188188
}
189189
};
190+
class Buf : public Str {
191+
public:
192+
Buf(const char *data, std::size_t length) : Str(data, length) { }
193+
virtual v8::Local<v8::Value> ToJs(ObjectMapper *m) const {
194+
Nan::EscapableHandleScope scope;
195+
return scope.Escape(Nan::CopyBuffer(data_, length_).ToLocalChecked());
196+
}
197+
};
198+
class OBuf : public OStr {
199+
public:
200+
OBuf(const char *data, std::size_t length) : OStr(data, length) { }
201+
virtual v8::Local<v8::Value> ToJs(ObjectMapper *m) const {
202+
Nan::EscapableHandleScope scope;
203+
return scope.Escape(Nan::CopyBuffer(data_, length_).ToLocalChecked());
204+
}
205+
};
190206
class Obj : public Base {
191207
objid_t id_;
192208
public:
@@ -252,6 +268,9 @@ class ZVal : public NonAssignable {
252268
SetOwnedString(*str, str.length());
253269
return;
254270
}
271+
} else if (node::Buffer::HasInstance(v)) {
272+
SetOwnedBuffer(node::Buffer::Data(v), node::Buffer::Length(v));
273+
return;
255274
} else if (v->IsObject()) {
256275
SetJsObject(m, Nan::To<v8::Object>(v).ToLocalChecked());
257276
return;
@@ -329,6 +348,16 @@ class ZVal : public NonAssignable {
329348
type_ = VALUE_OSTR;
330349
new (&ostr_) OStr(data, length);
331350
}
351+
void SetBuffer(const char *data, std::size_t length) {
352+
PerhapsDestroy();
353+
type_ = VALUE_BUF;
354+
new (&buf_) Buf(data, length);
355+
}
356+
void SetOwnedBuffer(const char *data, std::size_t length) {
357+
PerhapsDestroy();
358+
type_ = VALUE_OBUF;
359+
new (&obuf_) OBuf(data, length);
360+
}
332361
void SetJsObject(ObjectMapper *m, v8::Local<v8::Object> o) {
333362
SetJsObject(m->IdForJsObj(o));
334363
}
@@ -380,11 +409,13 @@ class ZVal : public NonAssignable {
380409
}
381410
enum ValueTypes {
382411
VALUE_EMPTY, VALUE_NULL, VALUE_BOOL, VALUE_INT, VALUE_DOUBLE,
383-
VALUE_STR, VALUE_OSTR, VALUE_JSOBJ, VALUE_PHPOBJ
412+
VALUE_STR, VALUE_OSTR, VALUE_BUF, VALUE_OBUF,
413+
VALUE_JSOBJ, VALUE_PHPOBJ
384414
} type_;
385415
union {
386416
int empty_; Null null_; Bool bool_; Int int_; Double double_;
387-
Str str_; OStr ostr_; JsObj jsobj_; PhpObj phpobj_;
417+
Str str_; OStr ostr_; Buf buf_; OBuf obuf_;
418+
JsObj jsobj_; PhpObj phpobj_;
388419
};
389420
const Base &AsBase() {
390421
switch(type_) {
@@ -402,6 +433,10 @@ class ZVal : public NonAssignable {
402433
return str_;
403434
case VALUE_OSTR:
404435
return ostr_;
436+
case VALUE_BUF:
437+
return buf_;
438+
case VALUE_OBUF:
439+
return obuf_;
405440
case VALUE_JSOBJ:
406441
return jsobj_;
407442
case VALUE_PHPOBJ:

test/context.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,9 @@ describe('Passing context object from JS to PHP', function() {
3333
d: (((1<<30)-1)*4),
3434
e: 1.5,
3535
f: 'abcdef \uD83D\uDCA9',
36-
g: { f: 1 }
36+
g: { f: 1 },
37+
h: function fname(x) { return x; },
38+
i: new Buffer('abc', 'utf8')
3739
}
3840
}).then(function(v) {
3941
out.toString().replace(/int\(4294967292\)/,'float(4294967292)')
@@ -44,7 +46,9 @@ describe('Passing context object from JS to PHP', function() {
4446
'float(4294967292)\n' +
4547
'float(1.5)\n' +
4648
'string(11) "abcdef \uD83D\uDCA9"\n' +
47-
'int(1)\n'
49+
'int(1)\n' +
50+
'string(5) "fname"\n' +
51+
'string(3) "abc"\n'
4852
);
4953
});
5054
});

test/context.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,6 @@
77
var_dump($c->e);
88
var_dump($c->f);
99
var_dump($c->g->f);
10+
var_dump($c->h->name);
11+
var_dump($c->i);
1012
?>

0 commit comments

Comments
 (0)