Published
Edited
Jun 23, 2022
Importers
25 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
proxy = deploy(
`proxy_${id}`, // Each proxy gets unique ID so they are not confused in notebooks with many
async (req, res, ctx) => {
try {
// Read the envelope
const { url, options } = JSON.parse(req.body, function (key, value) {
// the reviver function looks for the typed array flag
try {
if ("flag" in value && value.flag === "FLAG_TYPED_ARRAY") {
// if found, we convert it back to a typed array
return new window[value.constructor](value.data);
}
} catch (e) {}
// if flag not found no conversion is done
return value;
});

const secretParams = Object.keys(SECRET_PARAMS)
.map((param) => {
const secret = SECRET_PARAMS[param];
const value = ctx.secrets[secret];
return encodeURIComponent(param) + "=" + encodeURIComponent(value);
})
.join("&");

const decodedURL = new URL(url);
if ((secretParams || BASIC_AUTH) && !ALLOW_DOMAINS)
return res
.status(400)
.send("Must set ALLOW_DOMAINS when using secrets");
if (ALLOW_DOMAINS !== null && !ALLOW_DOMAINS.includes(decodedURL.host))
return res
.status(403)
.send(`${decodedURL.host} is not in ALLOW_DOMAINS set`);

options.headers = options.headers || {};
if (
options.headers["content-type"] === "application/x-www-form-urlencoded"
) {
options.body = (options.body || "") + "&" + secretParams;
} else {
decodedURL.search =
decodedURL.search.length > 0
? decodedURL.search + "&" + secretParams
: secretParams;
}

if (BASIC_AUTH && BASIC_AUTH.protocol === "RFC 7617") {
options.headers = options.headers || {};
const secret = ctx.secrets[BASIC_AUTH.passwordSecret];
const username = BASIC_AUTH.username;
options.headers["Authorization"] = `Basic ${btoa(
`${username}:${secret}`
)}`;
}

const response = await fetch(decodedURL, options);
const responseHeaders = Object.fromEntries(
Array.from(response.headers.entries()).map(([k, v]) => [
k.toLowerCase(),
v
])
);
delete responseHeaders["content-encoding"]; // Ensure we are not claiming to be gzipped
delete responseHeaders["content-length"]; // We switch to chunked
delete responseHeaders["access-control-allow-origin"]; // Remove any CORS
delete responseHeaders["x-frame-options"];
const headers = {
...responseHeaders,
...(options.responseHeaders || {}),
"transfer-encoding": "chunked"
};
Object.keys(headers).map((key) => {
if (headers[key]) res.header(key, headers[key]);
});

res.status(response.status);

const body = await response.body;
const reader = body.getReader();

let { done, value } = await reader.read();
while (!done) {
//await
res.write(value); // I think we shoudl await here but it breaks things if we do
({ done, value } = await reader.read());
}
res.end();
} catch (err) {
console.error(err);
res.end(); // Can't do much on a chunked response
}
},
{
host: "webcode.run",
modifiers: MODIFIERS,
reusable: true,
secrets: [
...Object.values(SECRET_PARAMS),
...array(BASIC_AUTH?.passwordSecret)
]
}
)
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more