Skip to content

Commit 598e32f

Browse files
authored
File: don't distinguish between encoded and non-encoded URLs.
2 parents 04b38e4 + e0f1ba4 commit 598e32f

File tree

14 files changed

+122
-4
lines changed

14 files changed

+122
-4
lines changed

VERSION.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
0.20251022.0
1+
0.20251027.0

src/file/file.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ File::Impl::Impl(const std::string &pFileNameOrUrl, bool pRetrieveContents)
2727
{
2828
// Check whether we are dealing with a local file or a URL.
2929

30-
auto [isLocalFile, fileNameOrUrl] = retrieveFileInfo(pFileNameOrUrl);
30+
auto [isLocalFile, fileNameOrUrl] = retrieveFileInfo(decodeUrl(pFileNameOrUrl));
3131

3232
if (isLocalFile) {
3333
mFilePath = stringToPath(fileNameOrUrl);

src/misc/utils.cpp

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,39 @@ bool fuzzyCompare(double pNb1, double pNb2)
145145
return std::fabs(pNb1 - pNb2) * ONE_TRILLION <= std::fmin(std::fabs(pNb1), std::fabs(pNb2));
146146
}
147147

148+
std::string encodeUrl(const std::string &pUrl)
149+
{
150+
std::ostringstream res;
151+
152+
for (const char c : pUrl) {
153+
if ((isalnum(c) != 0) || (std::string("!#$&'()*+,-./:;=?@_~").find(c) != std::string::npos)) {
154+
res << c;
155+
} else {
156+
res << '%' << std::uppercase << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(static_cast<unsigned char>(c));
157+
}
158+
}
159+
return res.str();
160+
}
161+
162+
std::string decodeUrl(const std::string &pUrl)
163+
{
164+
static constexpr auto BASE_16 = 16;
165+
166+
std::string res;
167+
168+
for (size_t i = 0; i < pUrl.size(); ++i) {
169+
if ((pUrl[i] == '%') && (i + 2 < pUrl.size()) && (std::isxdigit(pUrl[i + 1]) != 0) && (std::isxdigit(pUrl[i + 2]) != 0)) {
170+
res += static_cast<char>(std::stoi(pUrl.substr(i + 1, 2), nullptr, BASE_16));
171+
172+
i += 2;
173+
} else {
174+
res += pUrl[i];
175+
}
176+
}
177+
178+
return res;
179+
}
180+
148181
#ifdef BUILDING_USING_MSVC
149182
std::string forwardSlashPath(const std::string &pPath)
150183
{
@@ -436,7 +469,7 @@ std::tuple<bool, std::filesystem::path> downloadFile(const std::string &pUrl)
436469

437470
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
438471
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
439-
curl_easy_setopt(curl, CURLOPT_URL, pUrl.c_str());
472+
curl_easy_setopt(curl, CURLOPT_URL, encodeUrl(pUrl).c_str());
440473
curl_easy_setopt(curl, CURLOPT_WRITEDATA, static_cast<void *>(&file));
441474
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curlWriteFunction);
442475

src/misc/utils.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,9 @@ void LIBOPENCOR_UNIT_TESTING_EXPORT printArray(const std::string &pName, const D
7878

7979
bool LIBOPENCOR_UNIT_TESTING_EXPORT fuzzyCompare(double pNb1, double pNb2);
8080

81+
std::string LIBOPENCOR_UNIT_TESTING_EXPORT encodeUrl(const std::string &pUrl);
82+
std::string LIBOPENCOR_UNIT_TESTING_EXPORT decodeUrl(const std::string &pUrl);
83+
8184
#ifdef BUILDING_USING_MSVC
8285
std::string LIBOPENCOR_UNIT_TESTING_EXPORT forwardSlashPath(const std::string &pPath);
8386
#endif

tests/api/file/basictests.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,17 @@ TEST(BasicFileTest, remoteFile)
104104
EXPECT_FALSE(file->contents().empty());
105105
}
106106

107+
TEST(BasicFileTest, encodedRemoteFile)
108+
{
109+
auto file = libOpenCOR::File::create(libOpenCOR::ENCODED_REMOTE_FILE);
110+
111+
EXPECT_EQ(file->type(), libOpenCOR::File::Type::CELLML_FILE);
112+
EXPECT_NE(file->fileName(), "");
113+
EXPECT_EQ(file->url(), libOpenCOR::NON_ENCODED_REMOTE_FILE);
114+
EXPECT_EQ(file->path(), libOpenCOR::NON_ENCODED_REMOTE_FILE);
115+
EXPECT_FALSE(file->contents().empty());
116+
}
117+
107118
TEST(BasicFileTest, localVirtualFile)
108119
{
109120
auto file = libOpenCOR::File::create(libOpenCOR::resourcePath(libOpenCOR::UNKNOWN_FILE), false);

tests/bindings/javascript/file.basic.test.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,23 @@ test.describe('File basic tests', () => {
7777
assertIssues(loc, file, expectedUnknownFileIssues);
7878
});
7979

80+
test('Encoded remote file', () => {
81+
const file = new loc.File(utils.ENCODED_REMOTE_FILE);
82+
83+
assert.strictEqual(file.type.value, loc.File.Type.UNKNOWN_FILE.value);
84+
assert.strictEqual(file.fileName, '/some/path/file');
85+
assert.strictEqual(file.url, utils.NON_ENCODED_REMOTE_FILE);
86+
assert.strictEqual(file.path, utils.NON_ENCODED_REMOTE_FILE);
87+
assert.deepStrictEqual(file.contents(), utils.NO_CONTENTS);
88+
assertIssues(loc, file, expectedNoIssues);
89+
90+
file.setContents(unknownContentsPtr, utils.UNKNOWN_CONTENTS.length);
91+
92+
assert.strictEqual(file.type.value, loc.File.Type.UNKNOWN_FILE.value);
93+
assert.deepStrictEqual(file.contents(), utils.UNKNOWN_CONTENTS);
94+
assertIssues(loc, file, expectedUnknownFileIssues);
95+
});
96+
8097
test('File manager', () => {
8198
const fileManager = loc.FileManager.instance();
8299

tests/bindings/javascript/utils.in.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ export const HTTP_REMOTE_COMBINE_ARCHIVE =
3535
'http://raw.githubusercontent.com/opencor/libopencor/master/tests/res/cellml_2.omex';
3636
export const REMOTE_BASE_PATH = 'https://raw.githubusercontent.com/opencor/libopencor/master/tests/res';
3737
export const REMOTE_FILE = 'https://raw.githubusercontent.com/opencor/libopencor/master/tests/res/cellml_2.cellml';
38+
export const ENCODED_REMOTE_FILE =
39+
'https://models.physiomeproject.org/workspace/aed/@@rawfile/d4accf8429dbf5bdd5dfa1719790f361f5baddbe/FAIRDO%20BG%20example%203.1.cellml';
40+
export const NON_ENCODED_REMOTE_FILE =
41+
'https://models.physiomeproject.org/workspace/aed/@@rawfile/d4accf8429dbf5bdd5dfa1719790f361f5baddbe/FAIRDO BG example 3.1.cellml';
3842

3943
export const NO_CONTENTS = stringToArrayBuffer('');
4044
export const NULL_CHARACTER_CONTENTS = stringToArrayBuffer('\0');

tests/bindings/python/test_file_basic.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,16 @@ def test_remote_file():
104104
assert file.contents != []
105105

106106

107+
def test_encoded_remote_file():
108+
file = loc.File(utils.EncodedRemoteFile)
109+
110+
assert file.type == loc.File.Type.CellmlFile
111+
assert file.file_name != ""
112+
assert file.url == utils.NonEncodedRemoteFile
113+
assert file.path == utils.NonEncodedRemoteFile
114+
assert file.contents != []
115+
116+
107117
def test_local_virtual_file():
108118
file = loc.File(utils.resource_path(utils.UnknownFile), False)
109119

tests/bindings/python/utils.in.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@
5252
)
5353
RemoteBasePath = "https://raw.githubusercontent.com/opencor/libopencor/master/tests/res"
5454
RemoteFile = "https://raw.githubusercontent.com/opencor/libopencor/master/tests/res/cellml_2.cellml"
55+
EncodedRemoteFile = "https://models.physiomeproject.org/workspace/aed/@@rawfile/d4accf8429dbf5bdd5dfa1719790f361f5baddbe/FAIRDO%20BG%20example%203.1.cellml"
56+
NonEncodedRemoteFile = "https://models.physiomeproject.org/workspace/aed/@@rawfile/d4accf8429dbf5bdd5dfa1719790f361f5baddbe/FAIRDO BG example 3.1.cellml"
5557
UnknownRemoteFile = "https://raw.githubusercontent.com/opencor/libopencor/master/tests/res/unknown_file.txt"
5658
IrretrievableRemoteFile = "https://some.domain.com/irretrievable_file.txt"
5759

tests/misc/failingsimulationtests.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ TEST(FailingSimulationTest, basic)
2222
{
2323
// Default simulation.
2424

25-
auto file = libOpenCOR::File::create(libOpenCOR::resourcePath("../misc/res/tt04.omex"));
25+
auto file = libOpenCOR::File::create(libOpenCOR::resourcePath("misc/failablesimulation.omex"));
2626
auto document = libOpenCOR::SedDocument::create(file);
2727
auto instance = document->instantiate();
2828

0 commit comments

Comments
 (0)