github-actions[bot] commented on code in PR #69528:
URL: https://github.com/apache/doris/pull/69528#discussion_r4370544042


##########
be/src/io/fs/local_file_system.cpp:
##########
@@ -452,31 +452,206 @@ const std::shared_ptr<LocalFileSystem>& 
global_local_filesystem() {
     return local_fs;
 }
 
+Status LocalFileSystem::parse_local_path(const std::string& file_path, Path& 
local_path) {
+    // Reject embedded NULs before passing paths to filesystem APIs that use C 
strings.
+    if (file_path.empty() || file_path.find('\0') != std::string::npos) {
+        return Status::InvalidArgument("local file path must not be empty or 
contain NUL");
+    }
+    // Match URL preprocessing only for actual file URIs; bare paths keep 
literal whitespace.
+    const auto is_c0_or_space = [](unsigned char c) { return c <= 0x20; };
+    size_t begin = 0;
+    size_t end = file_path.size();
+    while (begin < end && is_c0_or_space(file_path[begin])) {
+        ++begin;
+    }
+    while (end > begin && is_c0_or_space(file_path[end - 1])) {
+        --end;
+    }
+    std::string uri_input;
+    for (size_t i = begin; i < end; ++i) {
+        if (file_path[i] != '\t' && file_path[i] != '\r' && file_path[i] != 
'\n') {
+            uri_input += file_path[i];
+        }
+    }
+    const bool is_file_uri = uri_input.size() >= 5 &&
+                             (uri_input[0] == 'f' || uri_input[0] == 'F') &&
+                             (uri_input[1] == 'i' || uri_input[1] == 'I') &&
+                             (uri_input[2] == 'l' || uri_input[2] == 'L') &&
+                             (uri_input[3] == 'e' || uri_input[3] == 'E') && 
uri_input[4] == ':';
+    std::string local_input = is_file_uri ? std::move(uri_input) : file_path;
+    if (is_file_uri) {
+        local_input.replace(0, 4, "file");
+        // File URLs treat raw backslashes as separators, including before the 
authority.
+        // Do this before conversion; percent-encoded backslashes must remain 
literal.
+        for (size_t i = 5; i < local_input.size(); ++i) {
+            if (local_input[i] == '\\') {
+                local_input[i] = '/';
+            }
+        }
+    }
+    const auto hex_digit = [](char c) -> int {
+        if (c >= '0' && c <= '9') return c - '0';
+        if (c >= 'a' && c <= 'f') return c - 'a' + 10;
+        if (c >= 'A' && c <= 'F') return c - 'A' + 10;
+        return -1;
+    };
+    const auto percent_decode = [&](const std::string& encoded) {
+        std::string decoded;
+        decoded.reserve(encoded.size());
+        for (size_t i = 0; i < encoded.size(); ++i) {
+            if (encoded[i] == '%' && i + 2 < encoded.size()) {
+                const int high = hex_digit(encoded[i + 1]);
+                const int low = hex_digit(encoded[i + 2]);
+                if (high >= 0 && low >= 0) {
+                    decoded += static_cast<char>((high << 4) | low);
+                    i += 2;
+                    continue;
+                }
+            }
+            decoded += encoded[i];
+        }
+        return decoded;
+    };
+    const auto is_drive = [](const std::string& segment) {
+        return segment.size() == 2 &&
+               ((segment[0] >= 'a' && segment[0] <= 'z') ||
+                (segment[0] >= 'A' && segment[0] <= 'Z')) &&
+               (segment[1] == ':' || segment[1] == '|');
+    };
+    bool empty_file_host = false;
+    if (is_file_uri && local_input.compare(5, 2, "//") == 0) {
+        const auto host_end = local_input.find_first_of("/?#", 7);
+        auto host = local_input.substr(7, host_end == std::string::npos ? 
host_end : host_end - 7);
+        if (is_drive(host)) {
+            // The URL parser treats a drive in the host position as the first 
path segment.
+            local_input.erase(5, 2);
+        } else {
+            host = percent_decode(host);
+            std::transform(host.begin(), host.end(), host.begin(), [](unsigned 
char c) {
+                return c >= 'A' && c <= 'Z' ? c + ('a' - 'A') : c;
+            });
+            empty_file_host = host.empty() || host == "localhost";
+        }
+    }
+    // Convert file: URIs to filesystem paths and reject remote schemes before 
any reader opens them.
+    RETURN_IF_ERROR(convert_to_abs_path(local_input, local_path));

Review Comment:
   [P2] Preserve SDK fallback identity for malformed file authorities
   
   With LOCAL enabled, an ADMIN/OPERATOR, and both BE cwd and 
user_files_secure_path set to /secure, consider 
file_path='file://host:80/secure/data.lance'. The [pinned URL parser rejects a 
colon in a file 
host](https://github.com/servo/rust-url/blob/v2.5.8/idna/src/uts46.rs#L343-L351),
 so [Lance falls back to treating the entire original string as a cwd-relative 
filesystem 
path](https://github.com/lance-format/lance/blob/68c12dfd7efe02f90ad2d7f3a239a7eb64884e57/rust/lance-io/src/object_store.rs#L528-L545):
 /secure/file:/host:80/secure/data.lance. This call instead strips host:80 
without validating it and resolves /secure/data.lance; resolve_dataset_uri sees 
success and skips the SDK parser. If those two in-root datasets contain 
different rows, schema discovery and scanning now silently select the other 
dataset. Preserve the SDK's parse/fallback identity before containment, or 
reject the malformed authority instead of rewriting it, and add a 
distinguishable-dataset collision case.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to