Skip to content

Commit f03c97a

Browse files
authored
Merge pull request #10541 from nextcloud/bugfix/hashVFS
fix(file-provider): preserve special characters in chunked upload paths
2 parents db43b87 + 7dc636d commit f03c97a

2 files changed

Lines changed: 40 additions & 12 deletions

File tree

shell_integration/MacOSX/NextcloudFileProviderKit/Sources/NextcloudFileProviderKit/Interface/NextcloudKit+RemoteInterface.swift

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,22 @@ import Foundation
77
import NextcloudCapabilitiesKit
88
import NextcloudKit
99

10+
func chunkedUploadRemotePathComponents(from remotePath: String) -> (serverUrl: String, destinationFileName: String)? {
11+
guard let separatorIndex = remotePath.lastIndex(of: "/") else {
12+
return nil
13+
}
14+
15+
let destinationFileNameIndex = remotePath.index(after: separatorIndex)
16+
guard destinationFileNameIndex < remotePath.endIndex else {
17+
return nil
18+
}
19+
20+
return (
21+
serverUrl: String(remotePath[..<separatorIndex]),
22+
destinationFileName: String(remotePath[destinationFileNameIndex...])
23+
)
24+
}
25+
1026
extension NextcloudKit: RemoteInterface {
1127
public func setDelegate(_ delegate: any NextcloudKitDelegate) {
1228
setup(delegate: delegate)
@@ -111,7 +127,7 @@ extension NextcloudKit: RemoteInterface {
111127
) async -> (account: String, file: NKFile?, nkError: NKError) {
112128
let logger = FileProviderLogger(category: "NextcloudKit+RemoteInterface", log: log)
113129

114-
guard let remoteUrl = URL(string: remotePath) else {
130+
guard let remotePathComponents = chunkedUploadRemotePathComponents(from: remotePath) else {
115131
return ("", nil, .urlError)
116132
}
117133
let localUrl = URL(fileURLWithPath: localPath)
@@ -136,17 +152,8 @@ extension NextcloudKit: RemoteInterface {
136152
}
137153
let fileChunksOutputDirectory = chunksOutputDirectoryUrl.path
138154
let fileName = localUrl.lastPathComponent
139-
let destinationFileName = remoteUrl.lastPathComponent
140-
guard let serverUrl = remoteUrl
141-
.deletingLastPathComponent()
142-
.absoluteString
143-
.removingPercentEncoding
144-
else {
145-
logger.error(
146-
"NCKit ext: Could not get server url from \(remotePath)"
147-
)
148-
return ("", nil, .urlError)
149-
}
155+
let destinationFileName = remotePathComponents.destinationFileName
156+
let serverUrl = remotePathComponents.serverUrl
150157
let fileChunks = remainingChunks.toNcKitChunks()
151158

152159
logger.info(

shell_integration/MacOSX/NextcloudFileProviderKit/Tests/NextcloudFileProviderKitTests/RemoteInterfaceTests.swift

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,27 @@ struct RemoteInterfaceExtensionTests {
1515
let testAccount = Account(user: "a1", id: "1", serverUrl: "example.com", password: "pass")
1616
let otherAccount = Account(user: "a2", id: "2", serverUrl: "example.com", password: "word")
1717

18+
@Test func chunkedUploadRemotePathComponentsPreserveFilenameCharacters() throws {
19+
let serverUrl = "https://cloud.example.com/remote.php/dav/files/user/comics"
20+
let fileNames = [
21+
"The Nightly News #001 (2011).cbz",
22+
"Question?.txt",
23+
"Literal%23Name.txt"
24+
]
25+
26+
for fileName in fileNames {
27+
let components = try #require(chunkedUploadRemotePathComponents(from: "\(serverUrl)/\(fileName)"))
28+
29+
#expect(components.serverUrl == serverUrl)
30+
#expect(components.destinationFileName == fileName)
31+
}
32+
}
33+
34+
@Test func chunkedUploadRemotePathComponentsRejectInvalidPaths() {
35+
#expect(chunkedUploadRemotePathComponents(from: "filename.txt") == nil)
36+
#expect(chunkedUploadRemotePathComponents(from: "https://cloud.example.com/") == nil)
37+
}
38+
1839
func capabilitiesFromMockJSON(jsonString: String = mockCapabilities) -> (Capabilities, Data) {
1940
let data = jsonString.data(using: .utf8)!
2041
let caps = Capabilities(data: data)!

0 commit comments

Comments
 (0)