// This is not a real HTTP server. We read blindly one time into 'requestBuf', // then write this fixed 'responseBuf'. The point of this benchmark is to // exercise the event loop in a simple yet semi-realistic way. const requestBuf = new Uint8Array(64 * 1024); const responseBuf = new Uint8Array( "HTTP/1.1 200 OK\r\nContent-Length: 12\r\n\r\nHello World\n" .split("") .map(c => c.charCodeAt(0)) ); const promiseMap = new Map(); let nextPromiseId = 1; function assert(cond) { if (!cond) { throw Error("assert"); } } function createResolvable() { let resolve; let reject; const promise = new Promise((res, rej) => { resolve = res; reject = rej; }); promise.resolve = resolve; promise.reject = reject; return promise; } const scratch32 = new Int32Array(3); const scratchBytes = new Uint8Array( scratch32.buffer, scratch32.byteOffset, scratch32.byteLength ); assert(scratchBytes.byteLength === 3 * 4); function send(promiseId, opId, rid, zeroCopy = null) { scratch32[0] = promiseId; scratch32[1] = rid; scratch32[2] = -1; return Deno.core.dispatch(opId, scratchBytes, zeroCopy); } /** Returns Promise */ function sendAsync(opId, rid, zeroCopy = null) { const promiseId = nextPromiseId++; const p = createResolvable(); const buf = send(promiseId, opId, rid, zeroCopy); if (buf) { const record = recordFromBuf(buf); // Sync result. p.resolve(record.result); } else { // Async result. promiseMap.set(promiseId, p); } return p; } /** Returns i32 number */ function sendSync(opId, rid) { const buf = send(0, opId, rid); const record = recordFromBuf(buf); return record[2]; } function recordFromBuf(buf) { assert(buf.byteLength === 3 * 4); return new Int32Array(buf.buffer, buf.byteOffset, buf.byteLength / 4); } function handleAsyncMsgFromRust(buf) { const record = recordFromBuf(buf); const p = promiseMap.get(record[0]); promiseMap.delete(record[0]); p.resolve(record[2]); } /** Listens on 0.0.0.0:4500, returns rid. */ function listen() { return sendSync(ops["listen"], -1); } /** Accepts a connection, returns rid. */ async function accept(rid) { return sendAsync(ops["accept"], rid); } /** * Reads a packet from the rid, presumably an http request. data is ignored. * Returns bytes read. */ async function read(rid, data) { return sendAsync(ops["read"], rid, data); } /** Writes a fixed HTTP response to the socket rid. Returns bytes written. */ async function write(rid, data) { return sendAsync(ops["write"], rid, data); } function close(rid) { return sendSync(ops["close"], rid); } async function serve(rid) { while (true) { const nread = await read(rid, requestBuf); if (nread <= 0) { break; } const nwritten = await write(rid, responseBuf); if (nwritten < 0) { break; } } close(rid); } let ops; async function main() { ops = Deno.core.ops(); for (const opName in ops) { Deno.core.setAsyncHandler(ops[opName], handleAsyncMsgFromRust); } Deno.core.print("http_bench.js start\n"); const listenerRid = listen(); Deno.core.print(`listening http://127.0.0.1:4544/ rid=${listenerRid}\n`); while (true) { const rid = await accept(listenerRid); // Deno.core.print(`accepted ${rid}`); if (rid < 0) { Deno.core.print(`accept error ${rid}`); return; } serve(rid); } } main();