From 535a8627776a3dfcb65cae112c497535cc56eac1 Mon Sep 17 00:00:00 2001 From: dab246 Date: Fri, 21 Feb 2025 11:37:54 +0700 Subject: [PATCH] TF-3493 Ensures that a URI always uses `wss://` or `ws://`, helping avoid the error `Unsupported URL scheme 'https'` Signed-off-by: dab246 --- .../extensions/uri_extension.dart | 7 ++++ .../extensions/uri_extension_test.dart | 33 ++++++++++++++++++- .../web_socket_datasource_impl.dart | 5 ++- 3 files changed, 43 insertions(+), 2 deletions(-) diff --git a/core/lib/presentation/extensions/uri_extension.dart b/core/lib/presentation/extensions/uri_extension.dart index 3668ea018..9da87b71f 100644 --- a/core/lib/presentation/extensions/uri_extension.dart +++ b/core/lib/presentation/extensions/uri_extension.dart @@ -30,4 +30,11 @@ extension URIExtension on Uri { return false; } } + + Uri ensureWebSocketUri() { + if (scheme == 'ws' || scheme == 'wss') { + return this; + } + return replace(scheme: 'wss'); + } } \ No newline at end of file diff --git a/core/test/presentation/extensions/uri_extension_test.dart b/core/test/presentation/extensions/uri_extension_test.dart index 8616c0d52..27dfc91b6 100644 --- a/core/test/presentation/extensions/uri_extension_test.dart +++ b/core/test/presentation/extensions/uri_extension_test.dart @@ -3,7 +3,6 @@ import 'package:core/presentation/extensions/uri_extension.dart'; import 'package:flutter_test/flutter_test.dart'; void main() { - group('method convertToQualifiedUrl test', () { test('convertToQualifiedUrl() should return qualified url when baseUrl is `https://domain.com` and sourceUrl is `https://domain.com/jmap`', () async { @@ -116,4 +115,36 @@ void main() { expect(qualifiedUrlResult, equals(qualifiedUrlExpected)); }); }); + + group('URIExtension.ensureWebSocketUri', () { + test('Should keep ws scheme unchanged', () { + final uri = Uri.parse('ws://example.com/socket'); + expect(uri.ensureWebSocketUri().toString(), 'ws://example.com/socket'); + }); + + test('Should keep wss scheme unchanged', () { + final uri = Uri.parse('wss://example.com/socket'); + expect(uri.ensureWebSocketUri().toString(), 'wss://example.com/socket'); + }); + + test('Should convert http to wss', () { + final uri = Uri.parse('http://example.com/socket'); + expect(uri.ensureWebSocketUri().toString(), 'wss://example.com/socket'); + }); + + test('Should convert https to wss', () { + final uri = Uri.parse('https://example.com/socket'); + expect(uri.ensureWebSocketUri().toString(), 'wss://example.com/socket'); + }); + + test('Should keep path and query parameters unchanged', () { + final uri = Uri.parse('http://example.com/socket?token=123'); + expect(uri.ensureWebSocketUri().toString(), 'wss://example.com/socket?token=123'); + }); + + test('Should handle URIs without a scheme (default to wss)', () { + final uri = Uri.parse('//example.com/socket'); + expect(uri.ensureWebSocketUri().toString(), 'wss://example.com/socket'); + }); + }); } \ No newline at end of file diff --git a/lib/features/push_notification/data/datasource_impl/web_socket_datasource_impl.dart b/lib/features/push_notification/data/datasource_impl/web_socket_datasource_impl.dart index 7ec0c650d..370b8798d 100644 --- a/lib/features/push_notification/data/datasource_impl/web_socket_datasource_impl.dart +++ b/lib/features/push_notification/data/datasource_impl/web_socket_datasource_impl.dart @@ -1,6 +1,8 @@ import 'dart:async'; +import 'package:core/presentation/extensions/uri_extension.dart'; +import 'package:core/utils/app_logger.dart'; import 'package:jmap_dart_client/jmap/account_id.dart'; import 'package:jmap_dart_client/jmap/core/capability/capability_identifier.dart'; import 'package:jmap_dart_client/jmap/core/capability/websocket_capability.dart'; @@ -26,7 +28,7 @@ class WebSocketDatasourceImpl implements WebSocketDatasource { final webSocketTicket = await _webSocketApi.getWebSocketTicket(session, accountId); final webSocketUri = _getWebSocketUri(session, accountId); final webSocketChannel = WebSocketChannel.connect( - Uri.parse('$webSocketUri?ticket=$webSocketTicket'), + Uri.parse('${webSocketUri.ensureWebSocketUri().toString()}?ticket=$webSocketTicket'), protocols: ["jmap"], ); @@ -54,6 +56,7 @@ class WebSocketDatasourceImpl implements WebSocketDatasource { if (webSocketCapability?.supportsPush != true) { throw WebSocketPushNotSupportedException(); } + log('WebSocketDatasourceImpl::_getWebSocketUri: webSocketCapability = ${webSocketCapability?.toJson()}'); final webSocketUri = webSocketCapability?.url; if (webSocketUri == null) throw WebSocketUriUnavailableException();