Skip to content

Commit 288491f

Browse files
authored
fix: http realm cache key with query params (#1896)
1 parent 3ecd707 commit 288491f

File tree

2 files changed

+39
-5
lines changed

2 files changed

+39
-5
lines changed

test-app/runtime/src/main/cpp/HMRSupport.cpp

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include "ArgConverter.h"
44
#include "JEnv.h"
55
#include <algorithm>
6+
#include <cctype>
67
#include <jni.h>
78
#include <unordered_map>
89
#include <cstring>
@@ -148,11 +149,43 @@ std::string CanonicalizeHttpUrlKey(const std::string& url) {
148149
size_t hashPos = url.find('#');
149150
std::string noHash = (hashPos == std::string::npos) ? url : url.substr(0, hashPos);
150151

151-
// Strip ?import markers and sort remaining query params for stability
152+
// Split into origin+path and query
152153
size_t qPos = noHash.find('?');
153-
if (qPos == std::string::npos) return noHash;
154-
std::string originAndPath = noHash.substr(0, qPos);
155-
std::string query = noHash.substr(qPos + 1);
154+
std::string originAndPath = (qPos == std::string::npos) ? noHash : noHash.substr(0, qPos);
155+
std::string query = (qPos == std::string::npos) ? std::string() : noHash.substr(qPos + 1);
156+
157+
// Normalize bridge endpoints to keep a single realm across HMR updates:
158+
// - /ns/rt/<ver> -> /ns/rt
159+
// - /ns/core/<ver> -> /ns/core
160+
size_t schemePos = originAndPath.find("://");
161+
if (schemePos != std::string::npos) {
162+
size_t pathStart = originAndPath.find('/', schemePos + 3);
163+
if (pathStart != std::string::npos) {
164+
std::string pathOnly = originAndPath.substr(pathStart);
165+
auto normalizeBridge = [&](const char* needle) {
166+
size_t nlen = strlen(needle);
167+
if (pathOnly.size() <= nlen) return false;
168+
if (pathOnly.compare(0, nlen, needle) != 0) return false;
169+
if (pathOnly.size() == nlen) return true;
170+
if (pathOnly[nlen] != '/') return false;
171+
size_t i = nlen + 1;
172+
size_t j = i;
173+
while (j < pathOnly.size() && isdigit((unsigned char)pathOnly[j])) j++;
174+
// Only normalize exact version segment: /ns/*/<digits> (no further segments)
175+
if (j == i) return false;
176+
if (j != pathOnly.size()) return false;
177+
originAndPath = originAndPath.substr(0, pathStart) + std::string(needle);
178+
return true;
179+
};
180+
if (!normalizeBridge("/ns/rt")) {
181+
normalizeBridge("/ns/core");
182+
}
183+
}
184+
}
185+
186+
if (query.empty()) return originAndPath;
187+
188+
// Strip ?import markers and sort remaining query params for stability
156189
std::vector<std::string> kept;
157190
size_t start = 0;
158191
while (start <= query.size()) {

test-app/runtime/src/main/cpp/ModuleInternalCallbacks.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -591,7 +591,8 @@ v8::MaybeLocal<v8::Module> ResolveModuleCallback(v8::Local<v8::Context> context,
591591
"}\n"
592592
"\n"
593593
"export function pathToFileURL(path) {\n"
594-
" return new URL('file://' + encodeURIComponent(path));\n"
594+
" const encoded = encodeURIComponent(path).replace(/%2F/g, '/');\n"
595+
" return new URL('file://' + encoded);\n"
595596
"}\n";
596597
} else if (builtinName == "module") {
597598
// Create a polyfill for node:module with createRequire

0 commit comments

Comments
 (0)