-
Notifications
You must be signed in to change notification settings - Fork 1
perf(capabilities): reduce http request overhead #127
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: bengl/native-spans
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| rm -f Cargo.lock | ||
| rm -rf prebuilds/* | ||
| npm run build-wasm | ||
| npx napi build --platform -p pipeline-native -o prebuilds/fastline --release |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,35 +1,67 @@ | ||
| const http = require('http'); | ||
| const https = require('https'); | ||
|
|
||
| module.exports.httpRequest = function (method, url, headersJson, body) { | ||
| const headers = JSON.parse(headersJson || '{}'); | ||
| headers['Content-Length'] = body.length; | ||
| const parsed = new URL(url); | ||
| const transport = parsed.protocol === 'https:' ? https : http; | ||
|
|
||
| return new Promise((resolve, reject) => { | ||
| const req = transport.request( | ||
| { | ||
| hostname: parsed.hostname, | ||
| port: parsed.port, | ||
| path: parsed.pathname + parsed.search, | ||
| method, | ||
| headers, | ||
| }, | ||
| (res) => { | ||
| const chunks = []; | ||
| res.on('data', (chunk) => chunks.push(chunk)); | ||
| res.on('end', () => { | ||
| resolve({ | ||
| status: res.statusCode, | ||
| headers: res.headers, | ||
| body: new Uint8Array(Buffer.concat(chunks)), | ||
| let storage = (f) => f(); | ||
|
|
||
| module.exports.setStorage = function (new_storage) { | ||
| storage = new_storage; | ||
| } | ||
|
|
||
| module.exports.httpRequest = function (host, port, isHttps, head_ptr, head_len, body_ptr, body_len, wasm_memory) { | ||
| const transport = isHttps ? https : http; | ||
|
|
||
| function isDetachedBufferError(err) { | ||
| return err instanceof TypeError && /detached/i.test(err.message); | ||
| } | ||
|
|
||
| function attempt() { | ||
| return new Promise((resolve, reject) => { | ||
| storage(() => { | ||
| // wasm_memory.buffer is replaced each time WebAssembly.Memory grows, so | ||
| // the views must be recreated on every attempt against the current buffer. | ||
| const headView = new Uint8Array(wasm_memory.buffer, head_ptr, head_len); | ||
| const bodyView = new Uint8Array(wasm_memory.buffer, body_ptr, body_len); | ||
|
|
||
| // host/port drive socket selection; method/path/headers are placeholders | ||
| // because we replace the rendered head below. | ||
| const req = transport.request({ host, port, method: 'POST', path: '/' }, (res) => { | ||
| const chunks = []; | ||
| res.on('data', (chunk) => chunks.push(chunk)); | ||
| res.on('end', () => { | ||
| const body = Buffer.concat(chunks) | ||
| resolve([ | ||
| res.statusCode, | ||
| res.rawHeaders, | ||
| new Uint8Array(body.buffer), | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Useful? React with 👍 / 👎. |
||
| ]); | ||
| }); | ||
| }); | ||
| req.on('error', reject); | ||
|
|
||
| // Bypass Node's headers: the Rust side has already produced the full | ||
| // request head in HTTP/1.1 wire format. Setting _header before write() | ||
| // makes write/end skip _implicitHeader and _send prepends our bytes. | ||
|
|
||
| try { | ||
| req._header = Buffer.from(headView); | ||
| req.write(bodyView); | ||
| req.end(); | ||
| } catch (err) { | ||
| reject(err); | ||
| } | ||
| }) | ||
| }); | ||
| } | ||
|
|
||
| function attemptWithRetry() { | ||
| return attempt().catch((err) => { | ||
| process.stderr.write("httpRequest error: " + err + "\n") | ||
| if (isDetachedBufferError(err)) { | ||
| return attemptWithRetry(); | ||
| } | ||
| ); | ||
| req.on('error', reject); | ||
| req.write(body); | ||
| req.end(); | ||
| }); | ||
| throw err; | ||
| }); | ||
| } | ||
|
|
||
| return attemptWithRetry(); | ||
| }; | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Response header parsing now calls
unwrap()on bothHeaderName::from_bytes(...)andHeaderValue::from_maybe_shared(...); any non-conformant upstream header (invalid token/value bytes) will panic this request path instead of returning anHttpError. This is a regression from the previous non-panicking behavior and can crash or trap the WASM execution when talking to unexpected or malformed HTTP servers.Useful? React with 👍 / 👎.