diff --git a/.github/renovate.json b/.github/renovate.json index 45b43bcfb72..6488cf8458d 100644 --- a/.github/renovate.json +++ b/.github/renovate.json @@ -12,11 +12,6 @@ "automerge": true }, "packageRules": [ - { - "matchFileNames": ["packages/nextcloud/**"], - "matchPackageNames": ["intl"], - "rangeStrategy": "widen" - }, { "matchManagers": ["pub"], "matchDatasources": ["dart-version", "flutter-version"], diff --git a/packages/neon_framework/lib/src/utils/request_manager.dart b/packages/neon_framework/lib/src/utils/request_manager.dart index ebc34ef83d5..d3b01195192 100644 --- a/packages/neon_framework/lib/src/utils/request_manager.dart +++ b/packages/neon_framework/lib/src/utils/request_manager.dart @@ -5,7 +5,7 @@ import 'package:built_value/serializer.dart'; import 'package:dynamite_runtime/http_client.dart'; import 'package:flutter/foundation.dart'; import 'package:http/http.dart' as http; -import 'package:intl/intl.dart'; +import 'package:http_parser/http_parser.dart'; import 'package:logging/logging.dart'; import 'package:meta/meta.dart'; import 'package:neon_framework/models.dart'; @@ -44,10 +44,6 @@ const kMaxTries = 3; /// Requests that take longer than this duration will be canceled. const kDefaultTimeout = Duration(seconds: 30); -/// Implements https://www.rfc-editor.org/rfc/rfc9110#name-date-time-formats -@visibleForTesting -final httpDateFormat = DateFormat('E, d MMM yyyy HH:mm:ss v', 'en_US'); - /// A singleton class that handles requests to the Nextcloud API. /// /// Requests need to be made through the [nextcloud](https://pub.dev/packages/nextcloud) @@ -369,7 +365,7 @@ class CacheParameters { /// Parse the cache parameters from HTTP response headers. factory CacheParameters.parseHeaders(Map headers) { - final expiry = headers.containsKey('expires') ? httpDateFormat.parse(headers['expires']! as String) : null; + final expiry = headers.containsKey('expires') ? parseHttpDate(headers['expires']! as String) : null; return CacheParameters( etag: headers['etag'] as String?, expires: _isExpired(expiry) ? null : expiry, diff --git a/packages/neon_framework/pubspec.yaml b/packages/neon_framework/pubspec.yaml index 7df3be7fc9d..2de7559d045 100644 --- a/packages/neon_framework/pubspec.yaml +++ b/packages/neon_framework/pubspec.yaml @@ -31,6 +31,7 @@ dependencies: flutter_zxing: ^1.0.0 go_router: ^13.0.0 http: ^1.0.0 + http_parser: ^4.0.0 image: ^4.0.0 intersperse: ^2.0.0 intl: ^0.18.0 diff --git a/packages/neon_framework/test/request_manager_test.dart b/packages/neon_framework/test/request_manager_test.dart index 6f2368961fc..2f350c66aed 100644 --- a/packages/neon_framework/test/request_manager_test.dart +++ b/packages/neon_framework/test/request_manager_test.dart @@ -8,6 +8,7 @@ import 'package:built_value/serializer.dart'; import 'package:dynamite_runtime/http_client.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:http/http.dart'; +import 'package:http_parser/http_parser.dart'; import 'package:mocktail/mocktail.dart'; import 'package:neon_framework/src/bloc/result.dart'; import 'package:neon_framework/src/utils/request_manager.dart'; @@ -681,7 +682,7 @@ void main() { test('cache ETag and Expires', () async { for (final (hours, isSet) in [(1, true), (-1, false)]) { - var newExpires = DateTime.now().add(Duration(hours: hours)); + var newExpires = DateTime.timestamp().add(Duration(hours: hours)); // Only precise to the second is allowed. newExpires = newExpires.subtract( Duration( @@ -713,7 +714,7 @@ void main() { headers: {}, rawHeaders: { 'etag': 'a', - 'expires': httpDateFormat.format(newExpires), + 'expires': formatHttpDate(newExpires), }, ), unwrap: (rawResponse) => rawResponse.body, diff --git a/packages/nextcloud/lib/src/webdav/file.dart b/packages/nextcloud/lib/src/webdav/file.dart index 1e1bf36ea88..a3f23dd9837 100644 --- a/packages/nextcloud/lib/src/webdav/file.dart +++ b/packages/nextcloud/lib/src/webdav/file.dart @@ -1,3 +1,4 @@ +import 'package:http_parser/http_parser.dart'; import 'package:nextcloud/src/webdav/client.dart'; import 'package:nextcloud/src/webdav/path_uri.dart'; import 'package:nextcloud/src/webdav/props.dart'; @@ -62,7 +63,7 @@ class WebDavFile { /// Last modified date of the file late final DateTime? lastModified = () { if (props.davgetlastmodified != null) { - return webdavDateFormat.parseUtc(props.davgetlastmodified!); + return parseHttpDate(props.davgetlastmodified!); } return null; }(); diff --git a/packages/nextcloud/lib/src/webdav/webdav.dart b/packages/nextcloud/lib/src/webdav/webdav.dart index 3c49ff0036a..e5d5a507351 100644 --- a/packages/nextcloud/lib/src/webdav/webdav.dart +++ b/packages/nextcloud/lib/src/webdav/webdav.dart @@ -1,7 +1,6 @@ // ignore_for_file: public_member_api_docs // coverage:ignore-file -import 'package:intl/intl.dart'; import 'package:meta/meta.dart'; import 'package:nextcloud/src/webdav/props.dart'; import 'package:xml/xml.dart'; @@ -9,9 +8,6 @@ import 'package:xml_annotation/xml_annotation.dart' as annotation; part 'webdav.g.dart'; -/// Format used in WebDAV -final webdavDateFormat = DateFormat('E, d MMM yyyy HH:mm:ss', 'en_US'); - const namespaceDav = 'DAV:'; const namespaceOwncloud = 'http://owncloud.org/ns'; const namespaceNextcloud = 'http://nextcloud.org/ns'; diff --git a/packages/nextcloud/pubspec.yaml b/packages/nextcloud/pubspec.yaml index 1f20806983b..25555c90c06 100644 --- a/packages/nextcloud/pubspec.yaml +++ b/packages/nextcloud/pubspec.yaml @@ -19,7 +19,7 @@ dependencies: crypton: ^2.0.0 dynamite_runtime: ^0.2.0 http: ^1.2.0 - intl: '>=0.17.0 <0.20.0' + http_parser: ^4.0.0 json_annotation: ^4.8.1 meta: ^1.0.0 universal_io: ^2.0.0 diff --git a/packages/nextcloud/test/webdav_test.dart b/packages/nextcloud/test/webdav_test.dart index 2be5e1e8e5a..40196d3630b 100644 --- a/packages/nextcloud/test/webdav_test.dart +++ b/packages/nextcloud/test/webdav_test.dart @@ -2,6 +2,7 @@ import 'dart:convert'; import 'dart:math'; import 'dart:typed_data'; +import 'package:http_parser/http_parser.dart'; import 'package:mocktail/mocktail.dart'; import 'package:nextcloud/nextcloud.dart'; import 'package:nextcloud_test/nextcloud_test.dart'; @@ -174,7 +175,7 @@ void main() { responses.singleWhere((response) => response.href!.endsWith('/Nextcloud.png')).propstats.first.prop; expect(props.nchaspreview, isTrue); expect(props.davgetcontenttype, 'image/png'); - expect(webdavDateFormat.parseUtc(props.davgetlastmodified!).isBefore(DateTime.now()), isTrue); + expect(parseHttpDate(props.davgetlastmodified!).isBefore(DateTime.now()), isTrue); expect(props.ocsize, 50598); }); @@ -241,7 +242,7 @@ void main() { expect(response.name, 'Nextcloud.png'); expect(response.isDirectory, isFalse); - expect(webdavDateFormat.parseUtc(response.props.davgetlastmodified!).isBefore(DateTime.now()), isTrue); + expect(parseHttpDate(response.props.davgetlastmodified!).isBefore(DateTime.now()), isTrue); expect(response.props.davgetetag, isNotEmpty); expect(response.props.davgetcontenttype, 'image/png'); expect(response.props.davgetcontentlength, 50598); @@ -301,7 +302,7 @@ void main() { expect(response.props.davgetcontenttype, isNull); expect( - webdavDateFormat.parseUtc(response.props.davgetlastmodified!).millisecondsSinceEpoch, + parseHttpDate(response.props.davgetlastmodified!).millisecondsSinceEpoch, closeTo(DateTime.now().millisecondsSinceEpoch, 10E3), ); expect(response.props.davresourcetype!.collection, isNotNull); @@ -370,7 +371,7 @@ void main() { .first .prop; expect(props.ocfavorite, 1); - expect(webdavDateFormat.parseUtc(props.davgetlastmodified!), lastModifiedDate); + expect(parseHttpDate(props.davgetlastmodified!), lastModifiedDate); expect(props.nccreationtime! * 1000, createdDate.millisecondsSinceEpoch); expect(props.ncuploadtime! * 1000, closeTo(uploadTime.millisecondsSinceEpoch, 10E3)); });