diff --git a/autotest/gcore/vsicurl.py b/autotest/gcore/vsicurl.py index 2bc0f2f2b4b4..9e46b2af9a24 100755 --- a/autotest/gcore/vsicurl.py +++ b/autotest/gcore/vsicurl.py @@ -1609,3 +1609,27 @@ def test_vsicurl_VSICURL_QUERY_STRING(server, filename, query_string): assert statres.size == 3 finally: gdal.SetPathSpecificOption(full_filename, "VSICURL_QUERY_STRING", None) + + +############################################################################### +# Test /vsicurl?header:foo=bar& + + +@gdaltest.enable_exceptions() +def test_vsicurl_header_option(server): + + gdal.VSICurlClearCache() + + handler = webserver.SequentialHandler() + handler.add( + "HEAD", + "/test_vsicurl_header_option.bin", + 200, + {"Content-Length": "3"}, + expected_headers={"foo": "bar", "Accept": "application/json"}, + ) + + with webserver.install_http_handler(handler): + full_filename = f"/vsicurl?header.foo=bar&header.Accept=application%2Fjson&url=http%3A%2F%2Flocalhost%3A{server.port}%2Ftest_vsicurl_header_option.bin" + statres = gdal.VSIStatL(full_filename) + assert statres.size == 3 diff --git a/doc/source/user/virtual_file_systems.rst b/doc/source/user/virtual_file_systems.rst index 1b1eb0526dd2..ddacadfc5b0c 100644 --- a/doc/source/user/virtual_file_systems.rst +++ b/doc/source/user/virtual_file_systems.rst @@ -387,6 +387,7 @@ Starting with GDAL 2.3, options can be passed in the filename with the following - referer=value: HTTP Referer header - cookie=value: HTTP Cookie header - header_file=value: Filename that contains one or several "Header: Value" lines +- header.=: HTTP request header of name and value . (GDAL >= 3.11). e.g. ``header.Accept=application%2Fjson`` - unsafessl=yes/no - low_speed_time=value - low_speed_limit=value diff --git a/port/cpl_vsil_curl.cpp b/port/cpl_vsil_curl.cpp index e259b4078aa0..9ea17cabf2c0 100644 --- a/port/cpl_vsil_curl.cpp +++ b/port/cpl_vsil_curl.cpp @@ -352,6 +352,7 @@ static std::string VSICurlGetURLFromFilename( } std::string osURL; + std::string osHeaders; for (int i = 0; papszTokens[i]; i++) { char *pszKey = nullptr; @@ -433,6 +434,13 @@ static std::string VSICurlGetURLFromFilename( *ppszPlanetaryComputerCollection = CPLStrdup(pszValue); } } + else if (STARTS_WITH(pszKey, "header.")) + { + osHeaders += (pszKey + strlen("header.")); + osHeaders += ':'; + osHeaders += pszValue; + osHeaders += "\r\n"; + } else { CPLError(CE_Warning, CPLE_NotSupported, @@ -442,6 +450,9 @@ static std::string VSICurlGetURLFromFilename( CPLFree(pszKey); } + if (paosHTTPOptions && !osHeaders.empty()) + paosHTTPOptions->SetNameValue("HEADERS", osHeaders.c_str()); + CSLDestroy(papszTokens); if (osURL.empty()) {