WebDav:listFolder - skip adding phantom items#12034
Conversation
|
I tried to avoid solutions with |
|
Tested on emulator 2024.04-186 with my cloud settings as on Kindle Scribe. |
|
Found two issues:
|
|
First case above happens because |
|
Second problems happens because I compare two different things now: I should probably strip all characters until including last slash. |
3373b99 to
c3d1bfb
Compare
|
Number 1 is fixed by using unencoded |
|
I know it looks way too hacky, any suggestions are welcome! Otherwise, emulator tests are great! |
|
It seems like It also seems that this is seven billion times simpler, which I like. Then again, I'm not familiar with DAV, so I'm unsure of whatever edge-cases it's currently trying to deal with. TL;DR: Does things horribly break with a simple diff --git a/frontend/apps/cloudstorage/webdavapi.lua b/frontend/apps/cloudstorage/webdavapi.lua
index f0d36696f..a3414b103 100644
--- a/frontend/apps/cloudstorage/webdavapi.lua
+++ b/frontend/apps/cloudstorage/webdavapi.lua
@@ -122,14 +122,12 @@ function WebDavApi:listFolder(address, user, pass, folder_path, folder_mode)
--logger.dbg("WebDav catalog item=", item)
-- <d:href> is the path and filename of the entry.
local item_fullpath = item:match("<[^:]*:href[^>]*>(.*)</[^:]*:href>")
- if string.sub( item_fullpath, -1 ) == "/" then
- item_fullpath = string.sub( item_fullpath, 1, -2 )
- end
- local is_current_dir = self:isCurrentDirectory( util.urlDecode(item_fullpath), address, folder_path )
- local item_name = util.urlDecode( FFIUtil.basename( item_fullpath ) )
+ local item_name = util.urlDecode(FFIUtil.basename(item_fullpath))
item_name = util.htmlEntitiesToUtf8(item_name)
+ local is_current_dir = item_name == string.sub(folder_path, -#item_name)
+
local is_not_collection = item:find("<[^:]*:resourcetype/>") or
item:find("<[^:]*:resourcetype></[^:]*:resourcetype>")(Stripping the trailing slash from |
|
@NiLuJe |
|
Ah, did you mean, this diff is applied on top of this PR? I applied it on fresh nightly |
@NiLuJe |
|
Sorry, I think I got it finally (need some sleep). |
|
@NiLuJe |
|
Overall diff looks much cleaner, thank you! |
|
Tested on emulator as well, all good. |
|
(removing those lines made the phantom folders come back) It works in the current state of this PR. |
|
Dunno anything about the issue, but after your changes |
That's possibly going to annoy Luacheck, for the record. I didn't mention that before ;p.
Yep, I'm not familiar with the codepaths involved (or DAV) so I can't really help there, but it is a concern I share ;). |
Huh. What if we stop doing stupid things like passing URL-encoded crap to
EDIT: HTML entities, too.
(Dropping the following call that used to be separate). |
|
No context braindump because the torturous logic made my brain hurt: diff --git a/frontend/apps/cloudstorage/webdav.lua b/frontend/apps/cloudstorage/webdav.lua
index bf9795879..be2a23e85 100644
--- a/frontend/apps/cloudstorage/webdav.lua
+++ b/frontend/apps/cloudstorage/webdav.lua
@@ -67,7 +67,7 @@ function WebDav:uploadFile(url, address, username, password, local_path, callbac
end
function WebDav:createFolder(url, address, username, password, folder_name, callback_close)
- local code_response = WebDavApi:createFolder(address .. WebDavApi:urlEncode(url .. "/" .. folder_name), username, password, folder_name)
+ local code_response = WebDavApi:createFolder(address .. WebDavApi.urlEncode(url .. "/" .. folder_name), username, password, folder_name)
if code_response == 201 then
if callback_close then
callback_close()
diff --git a/frontend/apps/cloudstorage/webdavapi.lua b/frontend/apps/cloudstorage/webdavapi.lua
index f0d36696f..e3d1e7333 100644
--- a/frontend/apps/cloudstorage/webdavapi.lua
+++ b/frontend/apps/cloudstorage/webdavapi.lua
@@ -12,44 +12,23 @@ local lfs = require("libs/libkoreader-lfs")
local WebDavApi = {
}
-function WebDavApi:getJoinedPath( address, path )
- local path_encoded = self:urlEncode( path ) or ""
- local address_strip = address:sub(-1) == "/" and address:sub(1, -2) or address
- local path_strip = path_encoded:sub(1, 1) == "/" and path_encoded:sub(2) or path_encoded
- return address_strip .. "/" .. path_strip
+-- Trim leading & trailing slashes from string `s` (based on util.trim)
+function WebDavApi.trim_slashes(s)
+ local from = s:match"^/*()"
+ return from > #s and "" or s:match(".*[^/]", from)
end
-function WebDavApi:isCurrentDirectory( current_item, address, path )
- local is_home, is_parent
- local home_path
- -- find first occurence of / after http(s)://
- local start = string.find( address, "/", 9 )
- if not start then
- home_path = "/"
- else
- home_path = string.sub( address, start )
+-- Trim trailing slashes from string `s` (based on util.rtrim)
+function WebDavApi.rtrim_slashes(s)
+ local n = #s
+ while n > 0 and s:find("^/", n) do
+ n = n - 1
end
- local item
- if string.sub( current_item, -1 ) == "/" then
- item = string.sub( current_item, 1, -2 )
- else
- item = current_item
- end
-
- if item == home_path then
- is_home = true
- else
- local temp_path = string.sub( item, string.len(home_path) + 1 )
- if string.sub( path, -1 ) == "/" then path = string.sub( path, 1, -2 ) end
- if temp_path == path then
- is_parent = true
- end
- end
- return is_home or is_parent
+ return s:sub(1, n)
end
--- version of urlEncode that doesn't encode the /
-function WebDavApi:urlEncode(url_data)
+-- Variant of util.urlEncode that doesn't encode the /
+function WebDavApi.urlEncode(url_data)
local char_to_hex = function(c)
return string.format("%%%02X", string.byte(c))
end
@@ -60,28 +39,30 @@ function WebDavApi:urlEncode(url_data)
return url_data
end
+-- Append path to address with a slash separator, trimming any unwanted slashes in the process.
+function WebDavApi:getJoinedPath(address, path)
+ local path_encoded = self.urlEncode(path) or ""
+ -- Strip leading & trailing slashes from `path`
+ local sane_path = self.trim_slashes(path_encoded)
+ -- Strip trailing slashes from `address` for now
+ local sane_address = self.rtrim_slashes(address)
+ -- Join our final URL
+ return sane_address .. "/" .. sane_path
+end
+
function WebDavApi:listFolder(address, user, pass, folder_path, folder_mode)
- local path = self:urlEncode( folder_path )
+ local path = self.urlEncode(folder_path) or ""
local webdav_list = {}
local webdav_file = {}
- local has_trailing_slash = false
- local has_leading_slash = false
- if string.sub( address, -1 ) == "/" then has_trailing_slash = true end
- if path == nil or path == "/" then
- path = ""
- elseif string.sub( path, 1, 1 ) == "/" then
- if has_trailing_slash then
- -- too many slashes, remove one
- path = string.sub( path, 2 )
- end
- has_leading_slash = true
- end
- if not has_trailing_slash and not has_leading_slash then
- address = address .. "/"
- end
- local webdav_url = address .. path
- if string.sub(webdav_url, -1) ~= "/" then
+ -- Strip leading & trailing slashes from `path`
+ path = self.trim_slashes(path)
+ -- Strip trailing slashes from `address` for now
+ address = self.rtrim_slashes(address)
+ -- Join our final URL, which *must* have a trailing / (it's a URL)
+ -- This is where we deviate from getJoinedPath ;).
+ local webdav_url = address .. "/" .. path
+ if webdav_url:sub(-1) ~= "/" then
webdav_url = webdav_url .. "/"
end
@@ -122,24 +103,18 @@ function WebDavApi:listFolder(address, user, pass, folder_path, folder_mode)
--logger.dbg("WebDav catalog item=", item)
-- <d:href> is the path and filename of the entry.
local item_fullpath = item:match("<[^:]*:href[^>]*>(.*)</[^:]*:href>")
- if string.sub( item_fullpath, -1 ) == "/" then
- item_fullpath = string.sub( item_fullpath, 1, -2 )
- end
- local is_current_dir = self:isCurrentDirectory( util.urlDecode(item_fullpath), address, folder_path )
-
- local item_name = util.urlDecode( FFIUtil.basename( item_fullpath ) )
- item_name = util.htmlEntitiesToUtf8(item_name)
-
+ local item_name = FFIUtil.basename(util.htmlEntitiesToUtf8(util.urlDecode(item_fullpath)))
+ local is_current_dir = item_name == string.sub(folder_path, -#item_name)
local is_not_collection = item:find("<[^:]*:resourcetype/>") or
- item:find("<[^:]*:resourcetype></[^:]*:resourcetype>")
+ item:find("<[^:]*:resourcetype></[^:]*:resourcetype>")
+ local item_path = path .. "/" .. item_name
- local item_path = (path == "" and has_trailing_slash) and item_name or path .. "/" .. item_name
if item:find("<[^:]*:collection[^<]*/>") then
item_name = item_name .. "/"
if not is_current_dir then
table.insert(webdav_list, {
text = item_name,
- url = util.urlDecode( item_path ),
+ url = item_path,
type = "folder",
})
end
@@ -147,7 +122,7 @@ function WebDavApi:listFolder(address, user, pass, folder_path, folder_mode)
or G_reader_settings:isTrue("show_unsupported")) then
table.insert(webdav_file, {
text = item_name,
- url = util.urlDecode( item_path ),
+ url = item_path,
type = "file",
})
end
diff --git a/frontend/util.lua b/frontend/util.lua
index 62c4cfd83..ddf2b906c 100644
--- a/frontend/util.lua
+++ b/frontend/util.lua
@@ -54,6 +54,23 @@ function util.trim(s)
return from > #s and "" or s:match(".*%S", from)
end
+--[[
+-- Trim leading & trailing character `c` from string `s`
+function util.trim_char(s, c)
+ local from = s:match"^"..c.."*()"
+ return from > #s and "" or s:match(".*[^"..c.."]", from)
+end
+
+-- Trim trailing character `c` from string `s`
+function util.rtrim_char(s, c)
+ local n = #s
+ while n > 0 and s:find("^"..c, n) do
+ n = n - 1
+ end
+ return s:sub(1, n)
+end
+--]]
+
--[[--
Splits a string by a pattern
|
|
(don't know how to convert this to draft, closing for now) |
|
I'm not sure if you can other than at the time of creation, maybe somewhere in the side menu. |
Yep, it's at the top of the right side-penel, bundled with the reviews. Rest assured, it takes me 35s to find it every time I look for it ;). |
|
You can set it a creation? I always switch it on after open the PR… |
|
Oh, right, the drop down on the 'Create pull request' button. TIL |
Yeah, I also routinely forget where that one is hidden, although it is slightly more obvious than the other one (maaaybe? :D) ;). |
Closes #12025
This is my try to fix the issue when a WebDav folder contains a phantom item with exact same name as that of the current folder itself. This phantom item is, of course, non-interactable.
So, in the
forloop where all url-decoded items are added to thewebdav_listtable, I check whether current-iteration item is phantom ("path to current item with trailing slash" is equal to "path of current folder") or real.Any suggestions or comments are appreciated! :D
This change is