Minimal HTTP fetch using java.net.* via JNI. Returns true on success (2xx) and non-empty body. Security: This is the single point of enforcement for remote module loading. In debug mode, all URLs are allowed. In production, checks security.allowRemoteModules and security.remoteModuleAllowlist from the app config.
| 216 | // In debug mode, all URLs are allowed. In production, checks security.allowRemoteModules |
| 217 | // and security.remoteModuleAllowlist from the app config. |
| 218 | bool HttpFetchText(const std::string& url, std::string& out, std::string& contentType, int& status) { |
| 219 | out.clear(); |
| 220 | contentType.clear(); |
| 221 | status = 0; |
| 222 | |
| 223 | // Security gate: check if remote module loading is allowed before any HTTP fetch. |
| 224 | if (!IsRemoteUrlAllowed(url)) { |
| 225 | status = 403; // Forbidden |
| 226 | if (IsScriptLoadingLogEnabled()) { |
| 227 | DEBUG_WRITE("[http-esm][security][blocked] %s", url.c_str()); |
| 228 | } |
| 229 | return false; |
| 230 | } |
| 231 | |
| 232 | try { |
| 233 | JEnv env; |
| 234 | |
| 235 | // Allow network operations on the current thread (dev-only HMR path) |
| 236 | // Some Android environments enforce StrictMode which throws NetworkOnMainThreadException |
| 237 | // when performing network I/O on the main thread. Since this fetch runs on the JS/V8 thread |
| 238 | // during development, explicitly relax the policy here. |
| 239 | { |
| 240 | jclass clsStrict = env.FindClass("android/os/StrictMode"); |
| 241 | jclass clsPolicyBuilder = env.FindClass("android/os/StrictMode$ThreadPolicy$Builder"); |
| 242 | if (clsStrict && clsPolicyBuilder) { |
| 243 | jmethodID builderCtor = env.GetMethodID(clsPolicyBuilder, "<init>", "()V"); |
| 244 | jobject builder = env.NewObject(clsPolicyBuilder, builderCtor); |
| 245 | if (builder) { |
| 246 | jmethodID permitAll = env.GetMethodID(clsPolicyBuilder, "permitAll", "()Landroid/os/StrictMode$ThreadPolicy$Builder;"); |
| 247 | jobject builder2 = permitAll ? env.CallObjectMethod(builder, permitAll) : builder; |
| 248 | jmethodID build = env.GetMethodID(clsPolicyBuilder, "build", "()Landroid/os/StrictMode$ThreadPolicy;"); |
| 249 | jobject policy = build ? env.CallObjectMethod(builder2 ? builder2 : builder, build) : nullptr; |
| 250 | if (policy) { |
| 251 | jmethodID setThreadPolicy = env.GetStaticMethodID(clsStrict, "setThreadPolicy", "(Landroid/os/StrictMode$ThreadPolicy;)V"); |
| 252 | if (setThreadPolicy) { |
| 253 | env.CallStaticVoidMethod(clsStrict, setThreadPolicy, policy); |
| 254 | } |
| 255 | } |
| 256 | } |
| 257 | } |
| 258 | } |
| 259 | |
| 260 | jclass clsURL = env.FindClass("java/net/URL"); |
| 261 | if (!clsURL) return false; |
| 262 | jmethodID urlCtor = env.GetMethodID(clsURL, "<init>", "(Ljava/lang/String;)V"); |
| 263 | jmethodID openConnection = env.GetMethodID(clsURL, "openConnection", "()Ljava/net/URLConnection;"); |
| 264 | jstring jUrlStr = env.NewStringUTF(url.c_str()); |
| 265 | jobject urlObj = env.NewObject(clsURL, urlCtor, jUrlStr); |
| 266 | |
| 267 | jobject conn = env.CallObjectMethod(urlObj, openConnection); |
| 268 | if (!conn) return false; |
| 269 | |
| 270 | jclass clsConn = env.GetObjectClass(conn); |
| 271 | jmethodID setConnectTimeout = env.GetMethodID(clsConn, "setConnectTimeout", "(I)V"); |
| 272 | jmethodID setReadTimeout = env.GetMethodID(clsConn, "setReadTimeout", "(I)V"); |
| 273 | jmethodID setDoInput = env.GetMethodID(clsConn, "setDoInput", "(Z)V"); |
| 274 | jmethodID setUseCaches = env.GetMethodID(clsConn, "setUseCaches", "(Z)V"); |
| 275 | jmethodID setReqProp = env.GetMethodID(clsConn, "setRequestProperty", "(Ljava/lang/String;Ljava/lang/String;)V"); |
no test coverage detected