diff --git a/src/matrix/net/HomeServerApi.js b/src/matrix/net/HomeServerApi.js index e6c97433..81da33d1 100644 --- a/src/matrix/net/HomeServerApi.js +++ b/src/matrix/net/HomeServerApi.js @@ -55,6 +55,26 @@ class RequestWrapper { } } +function encodeBody(body) { + if (body.nativeBlob && body.mimeType) { + const blob = body; + return { + mimeType: blob.mimeType, + body: blob, // will be unwrapped in request fn + length: blob.size + }; + } else if (typeof body === "object") { + const json = JSON.stringify(body); + return { + mimeType: "application/json", + body: json, + length: body.length + }; + } else { + throw new Error("Unknown body type: " + body); + } +} + export class HomeServerApi { constructor({homeServer, accessToken, request, createTimeout, reconnector}) { // store these both in a closure somehow so it's harder to get at in case of XSS? @@ -73,22 +93,24 @@ export class HomeServerApi { _baseRequest(method, url, queryParams, body, options, accessToken) { const queryString = encodeQueryParams(queryParams); url = `${url}?${queryString}`; - let bodyString; + let encodedBody; const headers = new Map(); if (accessToken) { headers.set("Authorization", `Bearer ${accessToken}`); } headers.set("Accept", "application/json"); if (body) { - headers.set("Content-Type", "application/json"); - bodyString = JSON.stringify(body); + const encoded = encodeBody(body); + headers.set("Content-Type", encoded.mimeType); + headers.set("Content-Length", encoded.length); + encodedBody = encoded.body; } const requestResult = this._requestFn(url, { method, headers, - body: bodyString, + body: encodedBody, timeout: options?.timeout, - format: "json" + format: "json" // response format }); const wrapper = new RequestWrapper(method, url, requestResult); diff --git a/src/platform/web/dom/request/fetch.js b/src/platform/web/dom/request/fetch.js index 13e2b32f..96c9ff9c 100644 --- a/src/platform/web/dom/request/fetch.js +++ b/src/platform/web/dom/request/fetch.js @@ -53,6 +53,10 @@ class RequestResult { export function createFetchRequest(createTimeout) { return function fetchRequest(url, {method, headers, body, timeout, format, cache = false}) { const controller = typeof AbortController === "function" ? new AbortController() : null; + // if a BlobHandle, take native blob + if (body?.nativeBlob) { + body = body.nativeBlob; + } let options = {method, body}; if (controller) { options = Object.assign(options, { diff --git a/src/platform/web/dom/request/xhr.js b/src/platform/web/dom/request/xhr.js index 9574c8cf..5ca2d460 100644 --- a/src/platform/web/dom/request/xhr.js +++ b/src/platform/web/dom/request/xhr.js @@ -52,6 +52,10 @@ function send(url, {method, headers, timeout, body, format}) { xhr.timeout = timeout; } + // if a BlobHandle, take native blob + if (body?.nativeBlob) { + body = body.nativeBlob; + } xhr.send(body || null); return xhr;