From 8796b8c58f2e3a78026c658bd0b0b87d909456d4 Mon Sep 17 00:00:00 2001 From: jld3103 Date: Fri, 3 Nov 2023 13:14:50 +0100 Subject: [PATCH] fix(nextcloud): Fix WebDAV path construction Signed-off-by: jld3103 --- packages/nextcloud/lib/src/webdav/client.dart | 19 +++------- packages/nextcloud/lib/src/webdav/file.dart | 14 +++----- packages/nextcloud/test/webdav_test.dart | 35 +++++++++++-------- 3 files changed, 30 insertions(+), 38 deletions(-) diff --git a/packages/nextcloud/lib/src/webdav/client.dart b/packages/nextcloud/lib/src/webdav/client.dart index a7dd64d3..9a2e9869 100644 --- a/packages/nextcloud/lib/src/webdav/client.dart +++ b/packages/nextcloud/lib/src/webdav/client.dart @@ -10,7 +10,7 @@ import 'package:universal_io/io.dart'; import 'package:xml/xml.dart' as xml; /// Base path used on the server -const String webdavBasePath = '/remote.php/webdav'; +final webdavBase = Uri(path: '/remote.php/webdav'); /// WebDavClient class class WebDavClient { @@ -65,20 +65,11 @@ class WebDavClient { @visibleForTesting // ignore: public_member_api_docs static Uri constructUri(final Uri baseURL, [final Uri? path]) { - assert( - path == null || path.path == '/' || !path.path.startsWith('/'), - "The path should not start a '/' unless indicating the root folder.", - ); - assert(!baseURL.path.endsWith('/'), "The baseURL should not end with a '/'."); - - final pathBuffer = StringBuffer(baseURL.path)..write(webdavBasePath); - if (path != null && path.path != '/') { - pathBuffer - ..write('/') - ..write(path.path); + final segments = baseURL.pathSegments.toList()..addAll(webdavBase.pathSegments); + if (path != null) { + segments.addAll(path.pathSegments); } - - return baseURL.replace(path: pathBuffer.toString()); + return baseURL.replace(pathSegments: segments.where((final s) => s.isNotEmpty)); } Future _parseResponse(final HttpClientResponse response) async => diff --git a/packages/nextcloud/lib/src/webdav/file.dart b/packages/nextcloud/lib/src/webdav/file.dart index cc163baf..7013c898 100644 --- a/packages/nextcloud/lib/src/webdav/file.dart +++ b/packages/nextcloud/lib/src/webdav/file.dart @@ -25,8 +25,8 @@ class WebDavFile { _response.propstats.singleWhere((final propstat) => propstat.status.contains('200')).prop; /// The path of file - late final String path = - Uri.decodeFull(_response.href!.substring(Uri.encodeFull(webdavBasePath).length, _response.href!.length)); + late final Uri path = + Uri(pathSegments: Uri(path: _response.href).pathSegments.sublist(webdavBase.pathSegments.length)); /// The fileid namespaced by the instance id, globally unique late final String? id = props.ocid; @@ -79,17 +79,11 @@ class WebDavFile { late final bool? hasPreview = props.nchaspreview; /// Returns the decoded name of the file / folder without the whole path - late final String name = () { - // normalized path (remove trailing slash) - final end = path.endsWith('/') ? path.length - 1 : path.length; - final segments = Uri.parse(path, 0, end).pathSegments; - - return segments.lastOrNull ?? ''; - }(); + late final String name = path.pathSegments.where((final s) => s.isNotEmpty).lastOrNull ?? ''; /// Whether the file is hidden. late final bool isHidden = name.startsWith('.'); /// Whether the file is a directory - late final bool isDirectory = (isCollection ?? false) || path.endsWith('/'); + late final bool isDirectory = (isCollection ?? false) || path.pathSegments.last.isEmpty; } diff --git a/packages/nextcloud/test/webdav_test.dart b/packages/nextcloud/test/webdav_test.dart index 523ddc40..0cba20be 100644 --- a/packages/nextcloud/test/webdav_test.dart +++ b/packages/nextcloud/test/webdav_test.dart @@ -9,18 +9,25 @@ import 'package:universal_io/io.dart'; import 'helper.dart'; void main() { - test('constructUri', () { - var baseURL = Uri.parse('http://cloud.example.com'); - expect(WebDavClient.constructUri(baseURL).toString(), '$baseURL$webdavBasePath'); - expect(WebDavClient.constructUri(baseURL, Uri(path: '/')).toString(), '$baseURL$webdavBasePath'); - expect(WebDavClient.constructUri(baseURL, Uri(path: 'test')).toString(), '$baseURL$webdavBasePath/test'); - - baseURL = Uri.parse('http://cloud.example.com/subdir'); - expect(WebDavClient.constructUri(baseURL, Uri(path: 'test')).toString(), '$baseURL$webdavBasePath/test'); - - expect(() => WebDavClient.constructUri(baseURL, Uri(path: '/test')), throwsA(isA())); - baseURL = Uri.parse('http://cloud.example.com/'); - expect(() => WebDavClient.constructUri(baseURL), throwsA(isA())); + group('constructUri', () { + for (final values in [ + ('http://cloud.example.com', 'http://cloud.example.com'), + ('http://cloud.example.com/', 'http://cloud.example.com'), + ('http://cloud.example.com/subdir', 'http://cloud.example.com/subdir'), + ('http://cloud.example.com/subdir/', 'http://cloud.example.com/subdir'), + ]) { + final baseURL = Uri.parse(values.$1); + final sanitizedBaseURL = Uri.parse(values.$2); + + test('$baseURL', () { + expect(WebDavClient.constructUri(baseURL).toString(), '$sanitizedBaseURL$webdavBase'); + expect(WebDavClient.constructUri(baseURL, Uri(path: '/')).toString(), '$sanitizedBaseURL$webdavBase'); + expect(WebDavClient.constructUri(baseURL, Uri(path: 'test')).toString(), '$sanitizedBaseURL$webdavBase/test'); + expect(WebDavClient.constructUri(baseURL, Uri(path: 'test/')).toString(), '$sanitizedBaseURL$webdavBase/test'); + expect(WebDavClient.constructUri(baseURL, Uri(path: '/test')).toString(), '$sanitizedBaseURL$webdavBase/test'); + expect(WebDavClient.constructUri(baseURL, Uri(path: '/test/')).toString(), '$sanitizedBaseURL$webdavBase/test'); + }); + } }); group( @@ -100,7 +107,7 @@ void main() { .toWebDavFiles() .single; - expect(response.path, '/Nextcloud.png'); + expect(response.path, Uri(path: 'Nextcloud.png')); expect(response.id, isNotEmpty); expect(response.fileId, isNotEmpty); expect(response.isCollection, isFalse); @@ -165,7 +172,7 @@ void main() { .toWebDavFiles() .single; - expect(response.path, '/test/'); + expect(response.path, Uri(path: 'test/')); expect(response.isCollection, isTrue); expect(response.mimeType, isNull); expect(response.size, data.lengthInBytes);