diff --git a/src/uds/transports/HTML5RDP/html5rdp.py b/src/uds/transports/HTML5RDP/html5rdp.py
index 53d544cd5..d8f885a68 100644
--- a/src/uds/transports/HTML5RDP/html5rdp.py
+++ b/src/uds/transports/HTML5RDP/html5rdp.py
@@ -381,12 +381,16 @@ def get_link(
'user': creds_info.username or None,
'password': creds_info.password or None,
'domain': creds_info.domain or None,
- 'nla': self.nla.as_bool(),
- 'verify_ssl': False,
'best_experience': self.best_experience.as_bool(),
- 'allow_audio': self.enable_audio.as_bool(),
- 'allow_mic': self.enable_microphone.as_bool(),
- 'allow_clipboard': self.allow_clipboard.as_bool(),
+ 'options': {
+ 'nla': self.nla.as_bool(),
+ 'verify_ssl': False,
+ },
+ 'redirections': {
+ 'clipboard': self.allow_clipboard.as_bool(),
+ 'audio': self.enable_audio.as_bool(),
+ 'mic': self.enable_microphone.as_bool(),
+ },
'allow_upload': self.enable_file_sharing.value in ('up', 'true'),
'allow_download': self.enable_file_sharing.value in ('down', 'true'),
'session_quality': self.session_quality.as_int(),
@@ -395,11 +399,11 @@ def get_link(
}
# Webcam redirection (matches Rust WebcamSettings). Only sent when enabled,
- # so the gateway keeps conn_data.webcam = None otherwise. WebcamSettings is
+ # so the gateway keeps redirections.webcam = None otherwise. WebcamSettings is
# #[serde(default)] on the gateway, so omitted keys fall back to its defaults.
# cam_width/cam_height are filled at runtime from the browser's getUserMedia.
if self.enable_webcam.as_bool():
- extra['webcam'] = {
+ extra['redirections']['webcam'] = {
'enabled': True,
'codec': self.webcam_codec.value,
'quality': self.webcam_quality.as_int(),
diff --git a/tests/transports/test_html5rdp.py b/tests/transports/test_html5rdp.py
index e537c7a22..1d24ac727 100644
--- a/tests/transports/test_html5rdp.py
+++ b/tests/transports/test_html5rdp.py
@@ -99,12 +99,12 @@ def test_transport_get_link(self) -> None:
link, extra = self._get_link_extra(transport, userservice, user, transport_model, ip='10.0.0.1')
self.assertEqual(extra['user'], 'testuser')
- self.assertEqual(extra['nla'], True)
- self.assertEqual(extra['verify_ssl'], False)
+ self.assertEqual(extra['options']['nla'], True)
+ self.assertEqual(extra['options']['verify_ssl'], False)
self.assertEqual(extra['best_experience'], True)
- self.assertEqual(extra['allow_audio'], True)
- self.assertEqual(extra['allow_mic'], False)
- self.assertEqual(extra['allow_clipboard'], True)
+ self.assertEqual(extra['redirections']['audio'], True)
+ self.assertEqual(extra['redirections']['mic'], False)
+ self.assertEqual(extra['redirections']['clipboard'], True)
self.assertEqual(extra['allow_upload'], True)
self.assertEqual(extra['allow_download'], True)
self.assertEqual(extra['session_quality'], 3)
@@ -141,11 +141,11 @@ def test_nla_direct(self) -> None:
transport.nla.value = True
_, extra = self._get_link_extra(transport, userservice, user, transport_model)
- self.assertTrue(extra['nla'])
+ self.assertTrue(extra['options']['nla'])
transport.nla.value = False
_, extra = self._get_link_extra(transport, userservice, user, transport_model)
- self.assertFalse(extra['nla'])
+ self.assertFalse(extra['options']['nla'])
def test_clipboard_direct(self) -> None:
"""Test allow_clipboard field maps directly to extra."""
@@ -154,11 +154,11 @@ def test_clipboard_direct(self) -> None:
transport.allow_clipboard.value = True
_, extra = self._get_link_extra(transport, userservice, user, transport_model)
- self.assertTrue(extra['allow_clipboard'])
+ self.assertTrue(extra['redirections']['clipboard'])
transport.allow_clipboard.value = False
_, extra = self._get_link_extra(transport, userservice, user, transport_model)
- self.assertFalse(extra['allow_clipboard'])
+ self.assertFalse(extra['redirections']['clipboard'])
def test_best_experience_direct(self) -> None:
"""Test best_experience field maps directly to extra."""
@@ -190,14 +190,20 @@ def test_extra_keys_match_rust_connection_data(self) -> None:
userservice, user, transport_model = _make_mocks()
_, extra = self._get_link_extra(transport, userservice, user, transport_model)
- # Fields in rdphtml5 ConnectionData (excluding host/port/notify_ticket set by broker)
+ # Top-level fields in rdphtml5 ConnectionData (excluding host/port/notify_ticket set by broker)
valid_rust_fields = {
- 'user_id', 'host', 'port', 'verify_ssl', 'user', 'password', 'domain',
- 'best_experience', 'nla', 'allow_audio', 'allow_mic', 'allow_clipboard',
+ 'user_id', 'host', 'port', 'user', 'password', 'domain',
+ 'best_experience', 'options', 'redirections',
'allow_upload', 'allow_download', 'session_quality',
'allow_quality_switch', 'notify_ticket', 'target_fps', 'rail_app',
'rail_args', 'rail_working_dir', 'title',
}
+ valid_options_fields = {'nla', 'verify_ssl'}
+ valid_redirections_fields = {'clipboard', 'audio', 'mic', 'webcam'}
for key in extra:
self.assertIn(key, valid_rust_fields, f"Extra key '{key}' not found in Rust ConnectionData")
+ for key in extra['options']:
+ self.assertIn(key, valid_options_fields, f"Options key '{key}' not found in Rust ConnectionData")
+ for key in extra['redirections']:
+ self.assertIn(key, valid_redirections_fields, f"Redirections key '{key}' not found in Rust ConnectionData")