Merge pull request #11469 from rouault/fix_11467

CPLGetPath()/CPLGetDirname(): make them work with /vsicurl? and URL encoded
This commit is contained in:
Even Rouault 2024-12-11 14:07:04 +01:00 committed by GitHub
commit 0ed4def329
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 116 additions and 6 deletions

View File

@ -1059,6 +1059,12 @@ TEST_F(test_cpl, CPLGetPath)
EXPECT_STREQ(CPLGetPath("/foo/bar"), "/foo");
EXPECT_STREQ(CPLGetPath("/vsicurl/http://example.com/foo/bar?suffix"),
"/vsicurl/http://example.com/foo?suffix");
EXPECT_STREQ(
CPLGetPath(
"/vsicurl?foo=bar&url=https%3A%2F%2Fraw.githubusercontent.com%"
"2FOSGeo%2Fgdal%2Fmaster%2Fautotest%2Fogr%2Fdata%2Fpoly.shp"),
"/vsicurl?foo=bar&url=https%3A%2F%2Fraw.githubusercontent.com%2FOSGeo%"
"2Fgdal%2Fmaster%2Fautotest%2Fogr%2Fdata");
}
TEST_F(test_cpl, CPLGetDirname)
@ -1067,6 +1073,12 @@ TEST_F(test_cpl, CPLGetDirname)
EXPECT_STREQ(CPLGetDirname("/foo/bar"), "/foo");
EXPECT_STREQ(CPLGetDirname("/vsicurl/http://example.com/foo/bar?suffix"),
"/vsicurl/http://example.com/foo?suffix");
EXPECT_STREQ(
CPLGetDirname(
"/vsicurl?foo=bar&url=https%3A%2F%2Fraw.githubusercontent.com%"
"2FOSGeo%2Fgdal%2Fmaster%2Fautotest%2Fogr%2Fdata%2Fpoly.shp"),
"/vsicurl?foo=bar&url=https%3A%2F%2Fraw.githubusercontent.com%2FOSGeo%"
"2Fgdal%2Fmaster%2Fautotest%2Fogr%2Fdata");
}
TEST_F(test_cpl, VSIGetDiskFreeSpace)

View File

@ -1745,6 +1745,35 @@ def test_ogr_shape_44():
assert f is not None, "did not get expected feature"
###############################################################################
# Test /vsicurl?url=
@pytest.mark.require_curl()
def test_ogr_shape_vsicurl_url():
conn = gdaltest.gdalurlopen(
"https://raw.githubusercontent.com/OSGeo/gdal/release/3.10/autotest/ogr/data/poly.shp"
)
if conn is None:
pytest.skip("cannot open URL")
conn.close()
ds = ogr.Open(
"/vsicurl?url=https%3A%2F%2Fraw.githubusercontent.com%2FOSGeo%2Fgdal%2Frelease%2F3.10%2Fautotest%2Fogr%2Fdata%2Fpoly.shp"
)
assert ds is not None
lyr = ds.GetLayer(0)
srs = lyr.GetSpatialRef()
wkt = srs.ExportToWkt()
assert wkt.find("OSGB") != -1, "did not get expected SRS"
f = lyr.GetNextFeature()
assert f is not None, "did not get expected feature"
###############################################################################
# Test ignored fields works ok on a shapefile.

View File

@ -128,6 +128,10 @@ static int CPLFindFilenameStart(const char *pszFilename, size_t nStart = 0)
const char *CPLGetPath(const char *pszFilename)
{
char *pszStaticResult = CPLGetStaticResult();
if (pszStaticResult == nullptr)
return CPLStaticBufferTooSmall(pszStaticResult);
size_t nSuffixPos = 0;
if (STARTS_WITH(pszFilename, "/vsicurl/http"))
{
@ -135,11 +139,41 @@ const char *CPLGetPath(const char *pszFilename)
if (pszQuestionMark)
nSuffixPos = static_cast<size_t>(pszQuestionMark - pszFilename);
}
else if (STARTS_WITH(pszFilename, "/vsicurl?") &&
strstr(pszFilename, "url="))
{
std::string osRet;
const CPLStringList aosTokens(
CSLTokenizeString2(pszFilename + strlen("/vsicurl?"), "&", 0));
for (int i = 0; i < aosTokens.size(); i++)
{
if (osRet.empty())
osRet = "/vsicurl?";
else
osRet += '&';
if (STARTS_WITH(aosTokens[i], "url=") &&
!STARTS_WITH(aosTokens[i], "url=/vsicurl"))
{
char *pszUnescaped =
CPLUnescapeString(aosTokens[i], nullptr, CPLES_URL);
char *pszPath = CPLEscapeString(
CPLGetPath(pszUnescaped + strlen("url=")), -1, CPLES_URL);
osRet += "url=";
osRet += pszPath;
CPLFree(pszPath);
CPLFree(pszUnescaped);
}
else
{
osRet += aosTokens[i];
}
}
CPLStrlcpy(pszStaticResult, osRet.c_str(), CPL_PATH_BUF_SIZE);
return pszStaticResult;
}
const int iFileStart = CPLFindFilenameStart(pszFilename, nSuffixPos);
char *pszStaticResult = CPLGetStaticResult();
if (pszStaticResult == nullptr || iFileStart >= CPL_PATH_BUF_SIZE)
if (iFileStart >= CPL_PATH_BUF_SIZE)
return CPLStaticBufferTooSmall(pszStaticResult);
CPLAssert(!(pszFilename >= pszStaticResult &&
@ -197,6 +231,10 @@ const char *CPLGetPath(const char *pszFilename)
const char *CPLGetDirname(const char *pszFilename)
{
char *pszStaticResult = CPLGetStaticResult();
if (pszStaticResult == nullptr)
return CPLStaticBufferTooSmall(pszStaticResult);
size_t nSuffixPos = 0;
if (STARTS_WITH(pszFilename, "/vsicurl/http"))
{
@ -204,11 +242,42 @@ const char *CPLGetDirname(const char *pszFilename)
if (pszQuestionMark)
nSuffixPos = static_cast<size_t>(pszQuestionMark - pszFilename);
}
else if (STARTS_WITH(pszFilename, "/vsicurl?") &&
strstr(pszFilename, "url="))
{
std::string osRet;
const CPLStringList aosTokens(
CSLTokenizeString2(pszFilename + strlen("/vsicurl?"), "&", 0));
for (int i = 0; i < aosTokens.size(); i++)
{
if (osRet.empty())
osRet = "/vsicurl?";
else
osRet += '&';
if (STARTS_WITH(aosTokens[i], "url=") &&
!STARTS_WITH(aosTokens[i], "url=/vsicurl"))
{
char *pszUnescaped =
CPLUnescapeString(aosTokens[i], nullptr, CPLES_URL);
char *pszPath = CPLEscapeString(
CPLGetDirname(pszUnescaped + strlen("url=")), -1,
CPLES_URL);
osRet += "url=";
osRet += pszPath;
CPLFree(pszPath);
CPLFree(pszUnescaped);
}
else
{
osRet += aosTokens[i];
}
}
CPLStrlcpy(pszStaticResult, osRet.c_str(), CPL_PATH_BUF_SIZE);
return pszStaticResult;
}
const int iFileStart = CPLFindFilenameStart(pszFilename, nSuffixPos);
char *pszStaticResult = CPLGetStaticResult();
if (pszStaticResult == nullptr || iFileStart >= CPL_PATH_BUF_SIZE)
if (iFileStart >= CPL_PATH_BUF_SIZE)
return CPLStaticBufferTooSmall(pszStaticResult);
CPLAssert(!(pszFilename >= pszStaticResult &&