|
3 | 3 | #include "ArgConverter.h" |
4 | 4 | #include "JEnv.h" |
5 | 5 | #include <algorithm> |
| 6 | +#include <cctype> |
6 | 7 | #include <jni.h> |
7 | 8 | #include <unordered_map> |
8 | 9 | #include <cstring> |
@@ -148,11 +149,43 @@ std::string CanonicalizeHttpUrlKey(const std::string& url) { |
148 | 149 | size_t hashPos = url.find('#'); |
149 | 150 | std::string noHash = (hashPos == std::string::npos) ? url : url.substr(0, hashPos); |
150 | 151 |
|
151 | | - // Strip ?import markers and sort remaining query params for stability |
| 152 | + // Split into origin+path and query |
152 | 153 | 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 |
156 | 189 | std::vector<std::string> kept; |
157 | 190 | size_t start = 0; |
158 | 191 | while (start <= query.size()) { |
|
0 commit comments