From aeb199d77faa5fdb37ada284861a56b4bc89dfa2 Mon Sep 17 00:00:00 2001 From: Mohit Beniwal Date: Fri, 10 Feb 2023 09:40:44 +0000 Subject: [PATCH] [FIX] web: prevent missing 'data' argument error while uploading empty file DataURL returns 'data:' in Chrome for empty files which is not valid dataURLas it expects 'data:;base64' . This DataURL method is used to obtain base64 representation of the file data,. That's why the 'data' argument is missing and error is being generated. Steps to reproduce: 1) Open Notes and create a new Note in Chrome. 2) Add a new attachment using /image command. 3) Add an empty file. By applying this,it will return proper format for empty file. sentry - 3749971166 closes odoo/odoo#120060 X-original-commit: fd6b904a97e7dab6e720675d9c805ed45eacef1e Signed-off-by: Samuel Degueldre --- addons/web/static/src/core/utils/urls.js | 9 ++++++++- addons/web/static/src/legacy/js/core/utils.js | 7 ++++++- addons/web/static/tests/core/utils/urls_tests.js | 8 +++++++- addons/web/static/tests/legacy/core/util_tests.js | 9 +++++++++ 4 files changed, 30 insertions(+), 3 deletions(-) diff --git a/addons/web/static/src/core/utils/urls.js b/addons/web/static/src/core/utils/urls.js index a46f215a062..0f2f32036fd 100644 --- a/addons/web/static/src/core/utils/urls.js +++ b/addons/web/static/src/core/utils/urls.js @@ -69,7 +69,14 @@ export function getDataURLFromFile(file) { } return new Promise((resolve, reject) => { const reader = new FileReader(); - reader.addEventListener("load", () => resolve(reader.result)); + reader.addEventListener("load", () => { + // Handle Chrome bug that creates invalid data URLs for empty files + if (reader.result === "data:") { + resolve(`data:${file.type};base64,`); + } else { + resolve(reader.result); + } + }); reader.addEventListener("abort", reject); reader.addEventListener("error", reject); reader.readAsDataURL(file); diff --git a/addons/web/static/src/legacy/js/core/utils.js b/addons/web/static/src/legacy/js/core/utils.js index 0759eb8d07e..de821729dc6 100644 --- a/addons/web/static/src/legacy/js/core/utils.js +++ b/addons/web/static/src/legacy/js/core/utils.js @@ -409,7 +409,12 @@ const utils = { return new Promise(function (resolve, reject) { var reader = new FileReader(); reader.addEventListener('load', function () { - resolve(reader.result); + // Handle Chrome bug that creates invalid data URLs for empty files + if (reader.result === "data:") { + resolve(`data:${file.type};base64,`); + } else { + resolve(reader.result); + } }); reader.addEventListener('abort', reject); reader.addEventListener('error', reject); diff --git a/addons/web/static/tests/core/utils/urls_tests.js b/addons/web/static/tests/core/utils/urls_tests.js index aa0fa379538..993a46fdfc8 100644 --- a/addons/web/static/tests/core/utils/urls_tests.js +++ b/addons/web/static/tests/core/utils/urls_tests.js @@ -1,7 +1,7 @@ /** @odoo-module */ import { browser } from "@web/core/browser/browser"; -import { getOrigin, url } from "@web/core/utils/urls"; +import { getDataURLFromFile, getOrigin, url } from "@web/core/utils/urls"; import { patchWithCleanup } from "../../helpers/utils"; QUnit.module("URLS", (hooks) => { @@ -59,4 +59,10 @@ QUnit.module("URLS", (hooks) => { }); assert.strictEqual(testUrl, "https://cors_server/cors_route/?my_param=1%2C2"); }); + + QUnit.test("getDataURLFromFile handles empty file", async (assert) => { + const emptyFile = new File([""], "empty.txt", { type: "text/plain" }); + const dataUrl = await getDataURLFromFile(emptyFile); + assert.strictEqual(dataUrl, "data:text/plain;base64,", "dataURL for empty file is not proper"); + }); }); diff --git a/addons/web/static/tests/legacy/core/util_tests.js b/addons/web/static/tests/legacy/core/util_tests.js index 3b5f6a0fad9..3288d0e0a53 100644 --- a/addons/web/static/tests/legacy/core/util_tests.js +++ b/addons/web/static/tests/legacy/core/util_tests.js @@ -1,6 +1,7 @@ /** @odoo-module **/ import utils from "web.utils"; +import { getDataURLFromFile } from "@web/core/utils/urls"; QUnit.module('core', {}, function () { @@ -301,4 +302,12 @@ QUnit.module('core', {}, function () { assert.deepEqual(sortBy(ints, null, 'desc'), [5, 2, 1]); assert.deepEqual(sortBy(objstrss, prop, 'desc'), [{ x: 'z' }, { x: 'b' }, { x: 'a' }]); }); + + QUnit.test('getDataURLFromFile handles empty file', async function (assert) { + assert.expect(1); + + const emptyFile = new File([""], "empty.txt", { type: "text/plain" }); + const dataUrl = await getDataURLFromFile(emptyFile); + assert.strictEqual(dataUrl, "data:text/plain;base64,", "dataURL for empty file is not proper"); + }); });