fix(sdk): Support unauthenticated media endpoint in Client::load_or_fetch_max_upload_size

Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
This commit is contained in:
Kévin Commaille
2025-08-12 11:44:53 +02:00
committed by Stefan Ceriu
parent 0fee716c1e
commit e0feebdb2b
2 changed files with 90 additions and 8 deletions

View File

@@ -45,6 +45,7 @@ use ruma::{
client::{
account::whoami,
alias::{create_alias, delete_alias, get_alias},
authenticated_media,
device::{delete_devices, get_devices, update_device},
directory::{get_public_rooms, get_public_rooms_filtered},
discovery::{
@@ -55,6 +56,7 @@ use ruma::{
error::ErrorKind,
filter::{create_filter::v3::Request as FilterUploadRequest, FilterDefinition},
knock::knock_room,
media,
membership::{join_room_by_id, join_room_by_id_or_alias},
room::create_room,
session::login::v3::DiscoveryInfo,
@@ -2792,12 +2794,22 @@ impl Client {
return Ok(data.to_owned());
}
let response = self
.send(ruma::api::client::authenticated_media::get_media_config::v1::Request::default())
.await?;
// Use the authenticated endpoint when the server supports it.
let supported_versions = self.supported_versions().await?;
let use_auth =
authenticated_media::get_media_config::v1::Request::is_supported(&supported_versions);
match max_upload_size_lock.set(response.upload_size) {
Ok(_) => Ok(response.upload_size),
let upload_size = if use_auth {
self.send(authenticated_media::get_media_config::v1::Request::default())
.await?
.upload_size
} else {
#[allow(deprecated)]
self.send(media::get_media_config::v3::Request::default()).await?.upload_size
};
match max_upload_size_lock.set(upload_size) {
Ok(_) => Ok(upload_size),
Err(error) => {
Err(Error::Media(MediaError::FetchMaxUploadSizeFailed(error.to_string())))
}
@@ -3803,7 +3815,9 @@ pub(crate) mod tests {
}
#[async_test]
async fn test_load_or_fetch_max_upload_size() {
async fn test_load_or_fetch_max_upload_size_with_auth_matrix_version() {
// The default Matrix version we use is 1.11 or higher, so authenticated media
// is supported.
let server = MatrixMockServer::new().await;
let client = server.client_builder().build().await;
@@ -3815,6 +3829,55 @@ pub(crate) mod tests {
assert_eq!(*client.inner.server_max_upload_size.lock().await.get().unwrap(), uint!(2));
}
#[async_test]
async fn test_load_or_fetch_max_upload_size_with_auth_stable_feature() {
// The server must advertise support for the stable feature for authenticated
// media support, so we mock the `GET /versions` response.
let server = MatrixMockServer::new().await;
let client = server.client_builder().no_server_versions().build().await;
server
.mock_versions()
.ok_custom(
&["v1.7", "v1.8", "v1.9", "v1.10"],
&[("org.matrix.msc3916.stable", true)].into(),
)
.named("versions")
.expect(1)
.mount()
.await;
assert!(!client.inner.server_max_upload_size.lock().await.initialized());
server.mock_authenticated_media_config().ok(uint!(2)).mock_once().mount().await;
client.load_or_fetch_max_upload_size().await.unwrap();
assert_eq!(*client.inner.server_max_upload_size.lock().await.get().unwrap(), uint!(2));
}
#[async_test]
async fn test_load_or_fetch_max_upload_size_no_auth() {
// The server must not support Matrix 1.11 or higher for unauthenticated
// media requests, so we mock the `GET /versions` response.
let server = MatrixMockServer::new().await;
let client = server.client_builder().no_server_versions().build().await;
server
.mock_versions()
.ok_custom(&["v1.1"], &Default::default())
.named("versions")
.expect(1)
.mount()
.await;
assert!(!client.inner.server_max_upload_size.lock().await.initialized());
server.mock_media_config().ok(uint!(2)).mock_once().mount().await;
client.load_or_fetch_max_upload_size().await.unwrap();
assert_eq!(*client.inner.server_max_upload_size.lock().await.get().unwrap(), uint!(2));
}
#[async_test]
async fn test_uploading_a_too_large_media_file() {
let server = MatrixMockServer::new().await;

View File

@@ -1226,12 +1226,19 @@ impl MatrixMockServer {
}
/// Create a prebuilt mock for the endpoint used to get the media config of
/// the homeserver.
/// the homeserver that requires authentication.
pub fn mock_authenticated_media_config(
&self,
) -> MockEndpoint<'_, AuthenticatedMediaConfigEndpoint> {
let mock = Mock::given(method("GET")).and(path("/_matrix/client/v1/media/config"));
self.mock_endpoint(mock, AuthenticatedMediaConfigEndpoint)
self.mock_endpoint(mock, AuthenticatedMediaConfigEndpoint).expect_default_access_token()
}
/// Create a prebuilt mock for the endpoint used to get the media config of
/// the homeserver without requiring authentication.
pub fn mock_media_config(&self) -> MockEndpoint<'_, MediaConfigEndpoint> {
let mock = Mock::given(method("GET")).and(path("/_matrix/media/v3/config"));
self.mock_endpoint(mock, MediaConfigEndpoint)
}
/// Create a prebuilt mock for the endpoint used to log into a session.
@@ -3495,6 +3502,18 @@ impl<'a> MockEndpoint<'a, AuthenticatedMediaConfigEndpoint> {
}
}
/// A prebuilt mock for `GET /_matrix/media/v3/config` request.
pub struct MediaConfigEndpoint;
impl<'a> MockEndpoint<'a, MediaConfigEndpoint> {
/// Returns a successful response with the provided max upload size.
pub fn ok(self, max_upload_size: UInt) -> MatrixMock<'a> {
self.respond_with(ResponseTemplate::new(200).set_body_json(json!({
"m.upload.size": max_upload_size,
})))
}
}
/// A prebuilt mock for `POST /login` requests.
pub struct LoginEndpoint;