From 653c3b1f62dd3efe1b466ca533935fe82a16eac7 Mon Sep 17 00:00:00 2001 From: XadillaX Date: Tue, 19 Jul 2022 15:13:56 +0800 Subject: [PATCH] buffer,lib: update atob to align wpt's base64.json Refs: https://html.spec.whatwg.org/multipage/webappapis.html#dom-atob-dev Refs: https://infra.spec.whatwg.org/#forgiving-base64-decode PR-URL: https://github.com/nodejs/node/pull/43901 Reviewed-By: James M Snell --- lib/buffer.js | 29 ++- test/fixtures/wpt/LICENSE.md | 2 +- test/fixtures/wpt/README.md | 1 + .../wpt/fetch/data-urls/resources/base64.json | 82 +++++++ .../fetch/data-urls/resources/data-urls.json | 214 ++++++++++++++++++ test/fixtures/wpt/versions.json | 4 + test/wpt/status/html/webappapis/atob.json | 3 - 7 files changed, 330 insertions(+), 5 deletions(-) create mode 100644 test/fixtures/wpt/fetch/data-urls/resources/base64.json create mode 100644 test/fixtures/wpt/fetch/data-urls/resources/data-urls.json diff --git a/lib/buffer.js b/lib/buffer.js index d5fde6debc2f74..7c0bbbc81c6398 100644 --- a/lib/buffer.js +++ b/lib/buffer.js @@ -1256,6 +1256,8 @@ const kForgivingBase64AllowedChars = [ 0x2F, // / 0x3D, // = ]; +const kEqualSignIndex = ArrayPrototypeIndexOf(kForgivingBase64AllowedChars, + 0x3D); function atob(input) { // The implementation here has not been performance optimized in any way and @@ -1267,6 +1269,7 @@ function atob(input) { input = `${input}`; let nonAsciiWhitespaceCharCount = 0; + let equalCharCount = 0; for (let n = 0; n < input.length; n++) { const index = ArrayPrototypeIndexOf( @@ -1277,13 +1280,36 @@ function atob(input) { // The first 5 elements of `kForgivingBase64AllowedChars` are // ASCII whitespace char codes. nonAsciiWhitespaceCharCount++; + + if (index === kEqualSignIndex) { + equalCharCount++; + } else if (equalCharCount) { + // The `=` char is only allowed at the end. + throw lazyDOMException('Invalid character', 'InvalidCharacterError'); + } + + if (equalCharCount > 2) { + // Only one more `=` is permitted after the first equal sign. + throw lazyDOMException('Invalid character', 'InvalidCharacterError'); + } } else if (index === -1) { throw lazyDOMException('Invalid character', 'InvalidCharacterError'); } } + let reminder = nonAsciiWhitespaceCharCount % 4; + + // See #2, #3, #4 - https://infra.spec.whatwg.org/#forgiving-base64 + if (!reminder) { + // Remove all trailing `=` characters and get the new reminder. + reminder = (nonAsciiWhitespaceCharCount - equalCharCount) % 4; + } else if (equalCharCount) { + // `=` should not in the input if there's a reminder. + throw lazyDOMException('Invalid character', 'InvalidCharacterError'); + } + // See #3 - https://infra.spec.whatwg.org/#forgiving-base64 - if (nonAsciiWhitespaceCharCount % 4 === 1) { + if (reminder === 1) { throw lazyDOMException( 'The string to be decoded is not correctly encoded.', 'InvalidCharacterError'); @@ -1298,6 +1324,7 @@ module.exports = { Buffer, SlowBuffer, transcode, + // Legacy kMaxLength, kStringMaxLength, diff --git a/test/fixtures/wpt/LICENSE.md b/test/fixtures/wpt/LICENSE.md index 39c46d03ac2988..ad4858c8745cfa 100644 --- a/test/fixtures/wpt/LICENSE.md +++ b/test/fixtures/wpt/LICENSE.md @@ -1,6 +1,6 @@ # The 3-Clause BSD License -Copyright © web-platform-tests contributors +Copyright 2019 web-platform-tests contributors Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/test/fixtures/wpt/README.md b/test/fixtures/wpt/README.md index 63175ead2a9c2d..a4ab2175fc65a2 100644 --- a/test/fixtures/wpt/README.md +++ b/test/fixtures/wpt/README.md @@ -15,6 +15,7 @@ Last update: - dom/abort: https://github.com/web-platform-tests/wpt/tree/c49cafb491/dom/abort - dom/events: https://github.com/web-platform-tests/wpt/tree/f8821adb28/dom/events - encoding: https://github.com/web-platform-tests/wpt/tree/c1b24fce6e/encoding +- fetch/data-urls/resources: https://github.com/web-platform-tests/wpt/tree/7c79d998ff/fetch/data-urls/resources - FileAPI: https://github.com/web-platform-tests/wpt/tree/3b279420d4/FileAPI - hr-time: https://github.com/web-platform-tests/wpt/tree/34cafd797e/hr-time - html/webappapis/atob: https://github.com/web-platform-tests/wpt/tree/f267e1dca6/html/webappapis/atob diff --git a/test/fixtures/wpt/fetch/data-urls/resources/base64.json b/test/fixtures/wpt/fetch/data-urls/resources/base64.json new file mode 100644 index 00000000000000..01f981a6502aec --- /dev/null +++ b/test/fixtures/wpt/fetch/data-urls/resources/base64.json @@ -0,0 +1,82 @@ +[ + ["", []], + ["abcd", [105, 183, 29]], + [" abcd", [105, 183, 29]], + ["abcd ", [105, 183, 29]], + [" abcd===", null], + ["abcd=== ", null], + ["abcd ===", null], + ["a", null], + ["ab", [105]], + ["abc", [105, 183]], + ["abcde", null], + ["𐀀", null], + ["=", null], + ["==", null], + ["===", null], + ["====", null], + ["=====", null], + ["a=", null], + ["a==", null], + ["a===", null], + ["a====", null], + ["a=====", null], + ["ab=", null], + ["ab==", [105]], + ["ab===", null], + ["ab====", null], + ["ab=====", null], + ["abc=", [105, 183]], + ["abc==", null], + ["abc===", null], + ["abc====", null], + ["abc=====", null], + ["abcd=", null], + ["abcd==", null], + ["abcd===", null], + ["abcd====", null], + ["abcd=====", null], + ["abcde=", null], + ["abcde==", null], + ["abcde===", null], + ["abcde====", null], + ["abcde=====", null], + ["=a", null], + ["=a=", null], + ["a=b", null], + ["a=b=", null], + ["ab=c", null], + ["ab=c=", null], + ["abc=d", null], + ["abc=d=", null], + ["ab\u000Bcd", null], + ["ab\u3000cd", null], + ["ab\u3001cd", null], + ["ab\tcd", [105, 183, 29]], + ["ab\ncd", [105, 183, 29]], + ["ab\fcd", [105, 183, 29]], + ["ab\rcd", [105, 183, 29]], + ["ab cd", [105, 183, 29]], + ["ab\u00a0cd", null], + ["ab\t\n\f\r cd", [105, 183, 29]], + [" \t\n\f\r ab\t\n\f\r cd\t\n\f\r ", [105, 183, 29]], + ["ab\t\n\f\r =\t\n\f\r =\t\n\f\r ", [105]], + ["A", null], + ["/A", [252]], + ["//A", [255, 240]], + ["///A", [255, 255, 192]], + ["////A", null], + ["/", null], + ["A/", [3]], + ["AA/", [0, 15]], + ["AAAA/", null], + ["AAA/", [0, 0, 63]], + ["\u0000nonsense", null], + ["abcd\u0000nonsense", null], + ["YQ", [97]], + ["YR", [97]], + ["~~", null], + ["..", null], + ["--", null], + ["__", null] +] diff --git a/test/fixtures/wpt/fetch/data-urls/resources/data-urls.json b/test/fixtures/wpt/fetch/data-urls/resources/data-urls.json new file mode 100644 index 00000000000000..f318d1f3e547d3 --- /dev/null +++ b/test/fixtures/wpt/fetch/data-urls/resources/data-urls.json @@ -0,0 +1,214 @@ +[ + ["data://test/,X", + "text/plain;charset=US-ASCII", + [88]], + ["data://test:test/,X", + null], + ["data:,X", + "text/plain;charset=US-ASCII", + [88]], + ["data:", + null], + ["data:text/html", + null], + ["data:text/html ;charset=x ", + null], + ["data:,", + "text/plain;charset=US-ASCII", + []], + ["data:,X#X", + "text/plain;charset=US-ASCII", + [88]], + ["data:,%FF", + "text/plain;charset=US-ASCII", + [255]], + ["data:text/plain,X", + "text/plain", + [88]], + ["data:text/plain ,X", + "text/plain", + [88]], + ["data:text/plain%20,X", + "text/plain%20", + [88]], + ["data:text/plain\f,X", + "text/plain%0c", + [88]], + ["data:text/plain%0C,X", + "text/plain%0c", + [88]], + ["data:text/plain;,X", + "text/plain", + [88]], + ["data:;x=x;charset=x,X", + "text/plain;x=x;charset=x", + [88]], + ["data:;x=x,X", + "text/plain;x=x", + [88]], + ["data:text/plain;charset=windows-1252,%C2%B1", + "text/plain;charset=windows-1252", + [194, 177]], + ["data:text/plain;Charset=UTF-8,%C2%B1", + "text/plain;charset=UTF-8", + [194, 177]], + ["data:text/plain;charset=windows-1252,áñçə💩", + "text/plain;charset=windows-1252", + [195, 161, 195, 177, 195, 167, 201, 153, 240, 159, 146, 169]], + ["data:text/plain;charset=UTF-8,áñçə💩", + "text/plain;charset=UTF-8", + [195, 161, 195, 177, 195, 167, 201, 153, 240, 159, 146, 169]], + ["data:image/gif,%C2%B1", + "image/gif", + [194, 177]], + ["data:IMAGE/gif,%C2%B1", + "image/gif", + [194, 177]], + ["data:IMAGE/gif;hi=x,%C2%B1", + "image/gif;hi=x", + [194, 177]], + ["data:IMAGE/gif;CHARSET=x,%C2%B1", + "image/gif;charset=x", + [194, 177]], + ["data: ,%FF", + "text/plain;charset=US-ASCII", + [255]], + ["data:%20,%FF", + "text/plain;charset=US-ASCII", + [255]], + ["data:\f,%FF", + "text/plain;charset=US-ASCII", + [255]], + ["data:%1F,%FF", + "text/plain;charset=US-ASCII", + [255]], + ["data:\u0000,%FF", + "text/plain;charset=US-ASCII", + [255]], + ["data:%00,%FF", + "text/plain;charset=US-ASCII", + [255]], + ["data:text/html ,X", + "text/html", + [88]], + ["data:text / html,X", + "text/plain;charset=US-ASCII", + [88]], + ["data:†,X", + "text/plain;charset=US-ASCII", + [88]], + ["data:†/†,X", + "%e2%80%a0/%e2%80%a0", + [88]], + ["data:X,X", + "text/plain;charset=US-ASCII", + [88]], + ["data:image/png,X X", + "image/png", + [88, 32, 88]], + ["data:application/javascript,X X", + "application/javascript", + [88, 32, 88]], + ["data:application/xml,X X", + "application/xml", + [88, 32, 88]], + ["data:text/javascript,X X", + "text/javascript", + [88, 32, 88]], + ["data:text/plain,X X", + "text/plain", + [88, 32, 88]], + ["data:unknown/unknown,X X", + "unknown/unknown", + [88, 32, 88]], + ["data:text/plain;a=\",\",X", + "text/plain;a=\"\"", + [34, 44, 88]], + ["data:text/plain;a=%2C,X", + "text/plain;a=%2C", + [88]], + ["data:;base64;base64,WA", + "text/plain", + [88]], + ["data:x/x;base64;base64,WA", + "x/x", + [88]], + ["data:x/x;base64;charset=x,WA", + "x/x;charset=x", + [87, 65]], + ["data:x/x;base64;charset=x;base64,WA", + "x/x;charset=x", + [88]], + ["data:x/x;base64;base64x,WA", + "x/x", + [87, 65]], + ["data:;base64,W%20A", + "text/plain;charset=US-ASCII", + [88]], + ["data:;base64,W%0CA", + "text/plain;charset=US-ASCII", + [88]], + ["data:x;base64x,WA", + "text/plain;charset=US-ASCII", + [87, 65]], + ["data:x;base64;x,WA", + "text/plain;charset=US-ASCII", + [87, 65]], + ["data:x;base64=x,WA", + "text/plain;charset=US-ASCII", + [87, 65]], + ["data:; base64,WA", + "text/plain;charset=US-ASCII", + [88]], + ["data:; base64,WA", + "text/plain;charset=US-ASCII", + [88]], + ["data: ;charset=x ; base64,WA", + "text/plain;charset=x", + [88]], + ["data:;base64;,WA", + "text/plain", + [87, 65]], + ["data:;base64 ,WA", + "text/plain;charset=US-ASCII", + [88]], + ["data:;base64 ,WA", + "text/plain;charset=US-ASCII", + [88]], + ["data:;base 64,WA", + "text/plain", + [87, 65]], + ["data:;BASe64,WA", + "text/plain;charset=US-ASCII", + [88]], + ["data:;%62ase64,WA", + "text/plain", + [87, 65]], + ["data:%3Bbase64,WA", + "text/plain;charset=US-ASCII", + [87, 65]], + ["data:;charset=x,X", + "text/plain;charset=x", + [88]], + ["data:; charset=x,X", + "text/plain;charset=x", + [88]], + ["data:;charset =x,X", + "text/plain", + [88]], + ["data:;charset= x,X", + "text/plain;charset=\" x\"", + [88]], + ["data:;charset=,X", + "text/plain", + [88]], + ["data:;charset,X", + "text/plain", + [88]], + ["data:;charset=\"x\",X", + "text/plain;charset=x", + [88]], + ["data:;CHARSET=\"X\",X", + "text/plain;charset=X", + [88]] +] diff --git a/test/fixtures/wpt/versions.json b/test/fixtures/wpt/versions.json index 3e223cd7d93b35..575090d02645ba 100644 --- a/test/fixtures/wpt/versions.json +++ b/test/fixtures/wpt/versions.json @@ -19,6 +19,10 @@ "commit": "c1b24fce6e625c1b79124a58f27bf9adce02d5d7", "path": "encoding" }, + "fetch/data-urls/resources": { + "commit": "7c79d998ff42e52de90290cb847d1b515b3b58f7", + "path": "fetch/data-urls/resources" + }, "FileAPI": { "commit": "3b279420d40afea32506e823f9ac005448f4f3d8", "path": "FileAPI" diff --git a/test/wpt/status/html/webappapis/atob.json b/test/wpt/status/html/webappapis/atob.json index 67345db26305af..2c63c0851048d8 100644 --- a/test/wpt/status/html/webappapis/atob.json +++ b/test/wpt/status/html/webappapis/atob.json @@ -1,5 +1,2 @@ { - "base64.any.js": { - "skip": "no such file or directory fetch/data-urls/resources/base64.json" - } }