Skip to content

Commit

Permalink
refactor(nextcloud)!: Migrate to DAV v2 endpoint for WebDAV
Browse files Browse the repository at this point in the history
Signed-off-by: provokateurin <[email protected]>
  • Loading branch information
provokateurin committed Oct 9, 2024
1 parent d7f1028 commit 1185498
Show file tree
Hide file tree
Showing 39 changed files with 285 additions and 211 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class WebDavFile {
return PathUri(
isAbsolute: false,
isDirectory: href.isDirectory,
pathSegments: href.pathSegments.sublist(webdavBase.pathSegments.length),
pathSegments: href.pathSegments.sublist(4),
);
}();

Expand Down
7 changes: 2 additions & 5 deletions packages/nextcloud/lib/src/api/webdav/utils/webdav_uri.dart
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
import 'package:meta/meta.dart';
import 'package:nextcloud/src/api/webdav/webdav.dart';

/// Base path used on the server
final webdavBase = PathUri.parse('/remote.php/webdav');

/// Constructs the uri for a webdav request for a given server [baseURL] and file [path].
@internal
Uri constructUri(Uri baseURL, [PathUri? path]) {
final segments = baseURL.pathSegments.toList()..addAll(webdavBase.pathSegments);
Uri constructUri(String username, Uri baseURL, [PathUri? path]) {
final segments = baseURL.pathSegments.toList()..addAll(['remote.php', 'dav', 'files', username]);
if (path != null) {
segments.addAll(path.pathSegments);
}
Expand Down
112 changes: 64 additions & 48 deletions packages/nextcloud/lib/src/api/webdav/webdav_client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import 'dart:typed_data';

import 'package:dynamite_runtime/http_client.dart';
import 'package:http/http.dart' as http;
import 'package:nextcloud/provisioning_api.dart' as provisioning_api;
import 'package:nextcloud/src/api/webdav/webdav.dart';
import 'package:nextcloud/utils.dart';
import 'package:universal_io/io.dart' show File, FileStat;
Expand Down Expand Up @@ -51,15 +52,26 @@ class WebDavClient extends DynamiteClient {
authentications: client.authentications,
);

Uri _constructUri([PathUri? path]) => constructUri(baseURL, path);
String? _username;

Future<Uri> _constructUri([PathUri? path]) async {
if (_username == null) {
final client = provisioning_api.$Client.fromClient(this);
// Consumers already need to catch http.ClientException so we don't need to catch and rethrow here.
final response = await client.users.getCurrentUser();
_username = response.body.ocs.data.id;
}

return constructUri(_username!, baseURL, path);
}

/// Returns a request to query the WebDAV capabilities of the server.
///
/// See:
/// * http://www.webdav.org/specs/rfc4918.html#HEADER_DAV for more information.
/// * [options] for a complete operation executing this request.
http.Request options_Request() {
final request = http.Request('OPTIONS', _constructUri());
Future<http.Request> options_Request() async {
final request = http.Request('OPTIONS', await _constructUri());

_addBaseHeaders(request);
return request;
Expand All @@ -71,7 +83,7 @@ class WebDavClient extends DynamiteClient {
/// * http://www.webdav.org/specs/rfc4918.html#HEADER_DAV for more information.
/// * [options_Request] for the request sent by this method.
Future<WebDavOptions> options() async {
final request = options_Request();
final request = await options_Request();

final streamedResponse = await httpClient.send(request);
if (streamedResponse.statusCode != 200) {
Expand All @@ -88,11 +100,11 @@ class WebDavClient extends DynamiteClient {
/// See:
/// * http://www.webdav.org/specs/rfc2518.html#METHOD_MKCOL and http://www.webdav.org/specs/rfc5689.html for more information.
/// * [mkcol] for a complete operation executing this request.
http.Request mkcol_Request(
Future<http.Request> mkcol_Request(
PathUri path, {
WebDavProp? set,
}) {
final request = http.Request('MKCOL', _constructUri(path));
}) async {
final request = http.Request('MKCOL', await _constructUri(path));
if (set != null) {
request.body = WebDavMkcol(
set: WebDavSet(prop: set),
Expand All @@ -114,7 +126,7 @@ class WebDavClient extends DynamiteClient {
PathUri path, {
WebDavProp? set,
}) async {
final request = mkcol_Request(
final request = await mkcol_Request(
path,
set: set,
);
Expand All @@ -133,8 +145,8 @@ class WebDavClient extends DynamiteClient {
/// See:
/// * http://www.webdav.org/specs/rfc2518.html#METHOD_DELETE for more information.
/// * [delete] for a complete operation executing this request.
http.Request delete_Request(PathUri path) {
final request = http.Request('DELETE', _constructUri(path));
Future<http.Request> delete_Request(PathUri path) async {
final request = http.Request('DELETE', await _constructUri(path));

_addBaseHeaders(request);
return request;
Expand All @@ -146,7 +158,7 @@ class WebDavClient extends DynamiteClient {
/// * http://www.webdav.org/specs/rfc2518.html#METHOD_DELETE for more information.
/// * [delete_Request] for the request sent by this method.
Future<http.StreamedResponse> delete(PathUri path) async {
final request = delete_Request(path);
final request = await delete_Request(path);

final streamedResponse = await httpClient.send(request);
if (streamedResponse.statusCode != 204) {
Expand All @@ -166,14 +178,14 @@ class WebDavClient extends DynamiteClient {
/// See:
/// * http://www.webdav.org/specs/rfc2518.html#METHOD_PUT for more information.
/// * [put] for a complete operation executing this request.
http.Request put_Request(
Future<http.Request> put_Request(
Uint8List localData,
PathUri path, {
DateTime? lastModified,
DateTime? created,
String? checksum,
}) {
final request = http.Request('PUT', _constructUri(path))..bodyBytes = localData;
}) async {
final request = http.Request('PUT', await _constructUri(path))..bodyBytes = localData;

_addUploadHeaders(
request,
Expand Down Expand Up @@ -202,7 +214,7 @@ class WebDavClient extends DynamiteClient {
DateTime? created,
String? checksum,
}) async {
final request = put_Request(
final request = await put_Request(
localData,
path,
lastModified: lastModified,
Expand Down Expand Up @@ -230,16 +242,16 @@ class WebDavClient extends DynamiteClient {
/// See:
/// * http://www.webdav.org/specs/rfc2518.html#METHOD_PUT for more information.
/// * [putStream] for a complete operation executing this request.
http.StreamedRequest putStream_Request(
Future<http.StreamedRequest> putStream_Request(
Stream<List<int>> localData,
PathUri path, {
required int contentLength,
DateTime? lastModified,
DateTime? created,
String? checksum,
void Function(double progress)? onProgress,
}) {
final request = http.StreamedRequest('PUT', _constructUri(path));
}) async {
final request = http.StreamedRequest('PUT', await _constructUri(path));

_addBaseHeaders(request);
_addUploadHeaders(
Expand Down Expand Up @@ -289,7 +301,7 @@ class WebDavClient extends DynamiteClient {
String? checksum,
void Function(double progress)? onProgress,
}) async {
final request = putStream_Request(
final request = await putStream_Request(
localData,
path,
lastModified: lastModified,
Expand Down Expand Up @@ -318,7 +330,7 @@ class WebDavClient extends DynamiteClient {
/// See:
/// * http://www.webdav.org/specs/rfc2518.html#METHOD_PUT for more information.
/// * [putFile] for a complete operation executing this request.
http.StreamedRequest putFile_Request(
Future<http.StreamedRequest> putFile_Request(
File file,
FileStat fileStat,
PathUri path, {
Expand Down Expand Up @@ -359,7 +371,7 @@ class WebDavClient extends DynamiteClient {
String? checksum,
void Function(double progress)? onProgress,
}) async {
final request = putFile_Request(
final request = await putFile_Request(
file,
fileStat,
path,
Expand All @@ -382,8 +394,8 @@ class WebDavClient extends DynamiteClient {
///
/// See:
/// * [get], [getStream] and [getFile] for complete operations executing this request.
http.Request get_Request(PathUri path) {
final request = http.Request('GET', _constructUri(path));
Future<http.Request> get_Request(PathUri path) async {
final request = http.Request('GET', await _constructUri(path));

_addBaseHeaders(request);
return request;
Expand Down Expand Up @@ -412,7 +424,7 @@ class WebDavClient extends DynamiteClient {
PathUri path, {
void Function(double progress)? onProgress,
}) async {
final request = get_Request(path);
final request = await get_Request(path);
final streamedResponse = await httpClient.send(request);
if (streamedResponse.statusCode != 200) {
final response = await http.Response.fromStream(streamedResponse);
Expand Down Expand Up @@ -469,12 +481,12 @@ class WebDavClient extends DynamiteClient {
/// See:
/// * http://www.webdav.org/specs/rfc2518.html#METHOD_PROPFIND for more information.
/// * [propfind] for a complete operation executing this request.
http.Request propfind_Request(
Future<http.Request> propfind_Request(
PathUri path, {
WebDavPropWithoutValues? prop,
WebDavDepth? depth,
}) {
final request = http.Request('PROPFIND', _constructUri(path))
}) async {
final request = http.Request('PROPFIND', await _constructUri(path))
..body = WebDavPropfind(prop: prop ?? const WebDavPropWithoutValues())
.toXmlElement(namespaces: namespaces)
.toXmlString();
Expand All @@ -499,7 +511,7 @@ class WebDavClient extends DynamiteClient {
WebDavPropWithoutValues? prop,
WebDavDepth? depth,
}) async {
final request = propfind_Request(
final request = await propfind_Request(
path,
prop: prop,
depth: depth,
Expand All @@ -521,12 +533,12 @@ class WebDavClient extends DynamiteClient {
/// See:
/// * https://docs.nextcloud.com/server/latest/developer_manual/client_apis/WebDAV/basic.html#listing-favorites for more information.
/// * [report] for a complete operation executing this request.
http.Request report_Request(
Future<http.Request> report_Request(
PathUri path,
WebDavOcFilterRules filterRules, {
WebDavPropWithoutValues? prop,
}) {
final request = http.Request('REPORT', _constructUri(path))
}) async {
final request = http.Request('REPORT', await _constructUri(path))
..body = WebDavOcFilterFiles(
filterRules: filterRules,
prop: prop ?? const WebDavPropWithoutValues(), // coverage:ignore-line
Expand All @@ -548,7 +560,7 @@ class WebDavClient extends DynamiteClient {
WebDavOcFilterRules filterRules, {
WebDavPropWithoutValues? prop,
}) async {
final request = report_Request(
final request = await report_Request(
path,
filterRules,
prop: prop,
Expand All @@ -571,12 +583,12 @@ class WebDavClient extends DynamiteClient {
/// See:
/// * http://www.webdav.org/specs/rfc2518.html#METHOD_PROPPATCH for more information.
/// * [proppatch] for a complete operation executing this request.
http.Request proppatch_Request(
Future<http.Request> proppatch_Request(
PathUri path, {
WebDavProp? set,
WebDavPropWithoutValues? remove,
}) {
final request = http.Request('PROPPATCH', _constructUri(path))
}) async {
final request = http.Request('PROPPATCH', await _constructUri(path))
..body = WebDavPropertyupdate(
set: set != null ? WebDavSet(prop: set) : null,
remove: remove != null ? WebDavRemove(prop: remove) : null,
Expand All @@ -600,7 +612,7 @@ class WebDavClient extends DynamiteClient {
WebDavProp? set,
WebDavPropWithoutValues? remove,
}) async {
final request = proppatch_Request(
final request = await proppatch_Request(
path,
set: set,
remove: remove,
Expand Down Expand Up @@ -630,14 +642,14 @@ class WebDavClient extends DynamiteClient {
/// See:
/// * http://www.webdav.org/specs/rfc2518.html#METHOD_MOVE for more information.
/// * [move] for a complete operation executing this request.
http.Request move_Request(
Future<http.Request> move_Request(
PathUri sourcePath,
PathUri destinationPath, {
bool overwrite = false,
}) {
final request = http.Request('MOVE', _constructUri(sourcePath));
}) async {
final request = http.Request('MOVE', await _constructUri(sourcePath));

_addCopyHeaders(
await _addCopyHeaders(
request,
destinationPath: destinationPath,
overwrite: overwrite,
Expand All @@ -658,7 +670,7 @@ class WebDavClient extends DynamiteClient {
PathUri destinationPath, {
bool overwrite = false,
}) async {
final request = move_Request(
final request = await move_Request(
sourcePath,
destinationPath,
overwrite: overwrite,
Expand All @@ -680,14 +692,14 @@ class WebDavClient extends DynamiteClient {
/// See:
/// * http://www.webdav.org/specs/rfc2518.html#METHOD_COPY for more information.
/// * [copy] for a complete operation executing this request.
http.Request copy_Request(
Future<http.Request> copy_Request(
PathUri sourcePath,
PathUri destinationPath, {
bool overwrite = false,
}) {
final request = http.Request('COPY', _constructUri(sourcePath));
}) async {
final request = http.Request('COPY', await _constructUri(sourcePath));

_addCopyHeaders(
await _addCopyHeaders(
request,
destinationPath: destinationPath,
overwrite: overwrite,
Expand All @@ -708,7 +720,7 @@ class WebDavClient extends DynamiteClient {
PathUri destinationPath, {
bool overwrite = false,
}) async {
final request = copy_Request(
final request = await copy_Request(
sourcePath,
destinationPath,
overwrite: overwrite,
Expand Down Expand Up @@ -756,8 +768,12 @@ class WebDavClient extends DynamiteClient {
request.headers['content-length'] = contentLength.toString();
}

void _addCopyHeaders(http.BaseRequest request, {required PathUri destinationPath, required bool overwrite}) {
request.headers['Destination'] = _constructUri(destinationPath).toString();
Future<void> _addCopyHeaders(
http.BaseRequest request, {
required PathUri destinationPath,
required bool overwrite,
}) async {
request.headers['Destination'] = (await _constructUri(destinationPath)).toString();
request.headers['Overwrite'] = overwrite ? 'T' : 'F';
}
}
14 changes: 8 additions & 6 deletions packages/nextcloud/test/api/webdav/utils/webdav_uri_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,30 +11,32 @@ void main() {
]) {
final baseURL = Uri.parse(values.$1);
final sanitizedBaseURL = Uri.parse(values.$2);
const username = 'admin';
const webdavBase = '/remote.php/dav/files/$username';

test(baseURL, () {
expect(
constructUri(baseURL).toString(),
constructUri(username, baseURL).toString(),
'$sanitizedBaseURL$webdavBase',
);
expect(
constructUri(baseURL, PathUri.parse('/')).toString(),
constructUri(username, baseURL, PathUri.parse('/')).toString(),
'$sanitizedBaseURL$webdavBase',
);
expect(
constructUri(baseURL, PathUri.parse('test')).toString(),
constructUri(username, baseURL, PathUri.parse('test')).toString(),
'$sanitizedBaseURL$webdavBase/test',
);
expect(
constructUri(baseURL, PathUri.parse('test/')).toString(),
constructUri(username, baseURL, PathUri.parse('test/')).toString(),
'$sanitizedBaseURL$webdavBase/test',
);
expect(
constructUri(baseURL, PathUri.parse('/test')).toString(),
constructUri(username, baseURL, PathUri.parse('/test')).toString(),
'$sanitizedBaseURL$webdavBase/test',
);
expect(
constructUri(baseURL, PathUri.parse('/test/')).toString(),
constructUri(username, baseURL, PathUri.parse('/test/')).toString(),
'$sanitizedBaseURL$webdavBase/test',
);
});
Expand Down
Loading

0 comments on commit 1185498

Please sign in to comment.