Skip to content

Commit

Permalink
make sure ipc with json serialization still works when bun is parent …
Browse files Browse the repository at this point in the history
…and not the child (#14756)

Co-authored-by: Jarred Sumner <[email protected]>
  • Loading branch information
nektro and Jarred-Sumner authored Jan 12, 2025
1 parent f9de8be commit 11feeff
Show file tree
Hide file tree
Showing 7 changed files with 97 additions and 13 deletions.
24 changes: 11 additions & 13 deletions src/bun.js/ipc.zig
Original file line number Diff line number Diff line change
Expand Up @@ -194,21 +194,19 @@ const json = struct {
// 1 is regular
// 2 is internal

pub fn decodeIPCMessage(
data: []const u8,
globalThis: *JSC.JSGlobalObject,
) IPCDecodeError!DecodeIPCMessageResult {
pub fn decodeIPCMessage(data: []const u8, globalThis: *JSC.JSGlobalObject) IPCDecodeError!DecodeIPCMessageResult {
if (bun.strings.indexOfChar(data, '\n')) |idx| {
var kind = data[0];
var json_data = data[1..idx];
var json_data = data[0..idx];

switch (kind) {
1, 2 => {},
2 => {
json_data = data[1..idx];
},
else => {
// if the message being recieved is from a node process then it wont have the leading marker byte
// assume full message will be json
// assume it's valid json with no header
// any error will be thrown by toJSByParseJSON below
kind = 1;
json_data = data[0..idx];
},
}

Expand All @@ -230,6 +228,7 @@ const json = struct {
}

const deserialized = str.toJSByParseJSON(globalThis);
if (deserialized == .zero) return error.InvalidFormat;

return switch (kind) {
1 => .{
Expand Down Expand Up @@ -259,13 +258,12 @@ const json = struct {

const slice = str.slice();

try writer.ensureUnusedCapacity(1 + slice.len + 1);
try writer.ensureUnusedCapacity(slice.len + 1);

writer.writeAssumeCapacity(&.{1});
writer.writeAssumeCapacity(slice);
writer.writeAssumeCapacity("\n");

return 1 + slice.len + 1;
return slice.len + 1;
}

pub fn serializeInternal(_: *IPCData, writer: anytype, global: *JSC.JSGlobalObject, value: JSValue) !usize {
Expand Down Expand Up @@ -860,7 +858,7 @@ fn NewNamedPipeIPCHandler(comptime Context: type) type {
// copy the remaining bytes to the start of the buffer
bun.copy(u8, ipc.incoming.ptr[0..slice.len], slice);
ipc.incoming.len = @truncate(slice.len);
log("hit NotEnoughBytes2", .{});
log("hit NotEnoughBytes3", .{});
return;
},
error.InvalidFormat => {
Expand Down
7 changes: 7 additions & 0 deletions test/js/bun/spawn/fixtures/ipc-child-bun.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
console.log("c start");
process.on("message", message => {
console.log("c", message);
process.send(message);
process.exit(0);
});
console.log("c end");
7 changes: 7 additions & 0 deletions test/js/bun/spawn/fixtures/ipc-child-node.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
console.log("c start");
process.on("message", message => {
console.log("c", message);
process.send(message);
process.exit(0);
});
console.log("c end");
14 changes: 14 additions & 0 deletions test/js/bun/spawn/fixtures/ipc-parent-bun.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
const path = require("node:path");

console.log("p start");
const child = Bun.spawn(["node", path.resolve(import.meta.dir, "ipc-child-node.js")], {
ipc(message) {
console.log("p", message);
process.exit(0);
},
stdio: ["ignore", "inherit", "inherit"],
serialization: "json",
});

child.send("I am your father");
console.log("p end");
15 changes: 15 additions & 0 deletions test/js/bun/spawn/fixtures/ipc-parent-node.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
const path = require("node:path");
const child_process = require("node:child_process");

console.log("p start");

const child = child_process.spawn(process.argv[2], [path.resolve(__dirname, "ipc-child-bun.js")], {
stdio: ["ignore", "inherit", "inherit", "ipc"],
});
child.on("message", message => {
console.log("p", message);
process.exit(0);
});

child.send("I am your father");
console.log("p end");
21 changes: 21 additions & 0 deletions test/js/bun/spawn/spawn.ipc.bun-node.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { spawn } from "bun";
import { test, expect, it } from "bun:test";
import { bunExe } from "harness";
import path from "path";

test("ipc with json serialization still works when bun is parent and not the child", async () => {
const child = Bun.spawn([bunExe(), path.resolve(import.meta.dir, "fixtures", "ipc-parent-bun.js")], {
stdio: ["ignore", "pipe", "pipe"],
});
await child.exited;
expect(await new Response(child.stdout).text()).toEqual(
`p start
p end
c start
c end
c I am your father
p I am your father
`,
);
expect(await new Response(child.stderr).text()).toEqual("");
});
22 changes: 22 additions & 0 deletions test/js/bun/spawn/spawn.ipc.node-bun.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { spawn } from "bun";
import { test, expect, it } from "bun:test";
import { bunExe, nodeExe } from "harness";
import path from "path";

test("ipc with json serialization still works when bun is not the parent and the child", async () => {
// prettier-ignore
const child = Bun.spawn(["node", "--no-warnings", path.resolve(import.meta.dir, "fixtures", "ipc-parent-node.js"), bunExe()], {
stdio: ["ignore", "pipe", "pipe"],
});
await child.exited;
expect(await new Response(child.stderr).text()).toEqual("");
expect(await new Response(child.stdout).text()).toEqual(
`p start
p end
c start
c end
c I am your father
p I am your father
`,
);
});

0 comments on commit 11feeff

Please sign in to comment.