|
@@ -1133,17 +1133,27 @@ static JSValue js_http_request(JSContext* ctx, JSValue this_val, int argc, JSVal
|
|
|
content_type = resp_headers["content-type"].get<std::string>();
|
|
content_type = resp_headers["content-type"].get<std::string>();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ // Binary-safe view of the body. "data" below goes through JS_NewString*, which
|
|
|
|
|
+ // UTF-8 validates and would replace every invalid byte, so it cannot carry
|
|
|
|
|
+ // images or other binary payloads. dataBase64 preserves the raw bytes.
|
|
|
|
|
+ JS_SetPropertyStr(ctx, result, "dataBase64",
|
|
|
|
|
+ JS_NewString(ctx, base64Encode(response.body).c_str()));
|
|
|
|
|
+
|
|
|
if (content_type.find("application/json") != std::string::npos && !response.body.empty()) {
|
|
if (content_type.find("application/json") != std::string::npos && !response.body.empty()) {
|
|
|
JSValue data = JS_ParseJSON(ctx, response.body.c_str(), response.body.size(), "<body>");
|
|
JSValue data = JS_ParseJSON(ctx, response.body.c_str(), response.body.size(), "<body>");
|
|
|
if (JS_IsException(data)) {
|
|
if (JS_IsException(data)) {
|
|
|
// JSON parse failed, use as string
|
|
// JSON parse failed, use as string
|
|
|
JS_FreeValue(ctx, JS_GetException(ctx));
|
|
JS_FreeValue(ctx, JS_GetException(ctx));
|
|
|
- JS_SetPropertyStr(ctx, result, "data", JS_NewString(ctx, response.body.c_str()));
|
|
|
|
|
|
|
+ JS_SetPropertyStr(ctx, result, "data",
|
|
|
|
|
+ JS_NewStringLen(ctx, response.body.data(), response.body.size()));
|
|
|
} else {
|
|
} else {
|
|
|
JS_SetPropertyStr(ctx, result, "data", data);
|
|
JS_SetPropertyStr(ctx, result, "data", data);
|
|
|
}
|
|
}
|
|
|
} else {
|
|
} else {
|
|
|
- JS_SetPropertyStr(ctx, result, "data", JS_NewString(ctx, response.body.c_str()));
|
|
|
|
|
|
|
+ // JS_NewStringLen rather than c_str(): a NUL byte in the body would
|
|
|
|
|
+ // otherwise truncate the string at that point.
|
|
|
|
|
+ JS_SetPropertyStr(ctx, result, "data",
|
|
|
|
|
+ JS_NewStringLen(ctx, response.body.data(), response.body.size()));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
return result;
|
|
@@ -1217,6 +1227,17 @@ void ScriptEngine::setupBuiltinAPIs() {
|
|
|
|
|
|
|
|
// smartbotic.log
|
|
// smartbotic.log
|
|
|
JSValue log = JS_NewObject(ctx);
|
|
JSValue log = JS_NewObject(ctx);
|
|
|
|
|
+ JS_SetPropertyStr(ctx, log, "debug", JS_NewCFunction(ctx, [](JSContext* ctx, JSValue this_val, int argc, JSValue* argv) -> JSValue {
|
|
|
|
|
+ if (argc > 0) {
|
|
|
|
|
+ const char* str = JS_ToCString(ctx, argv[0]);
|
|
|
|
|
+ if (str) {
|
|
|
|
|
+ LOG_DEBUG("[JS] {}", str);
|
|
|
|
|
+ JS_FreeCString(ctx, str);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ return JS_UNDEFINED;
|
|
|
|
|
+ }, "debug", 1));
|
|
|
|
|
+
|
|
|
JS_SetPropertyStr(ctx, log, "info", JS_NewCFunction(ctx, [](JSContext* ctx, JSValue this_val, int argc, JSValue* argv) -> JSValue {
|
|
JS_SetPropertyStr(ctx, log, "info", JS_NewCFunction(ctx, [](JSContext* ctx, JSValue this_val, int argc, JSValue* argv) -> JSValue {
|
|
|
if (argc > 0) {
|
|
if (argc > 0) {
|
|
|
const char* str = JS_ToCString(ctx, argv[0]);
|
|
const char* str = JS_ToCString(ctx, argv[0]);
|