Changeset 195694 in webkit


Ignore:
Timestamp:
Jan 27, 2016 2:37:48 PM (8 years ago)
Author:
Chris Dumez
Message:

window.atob() should ignore spaces in input
https://bugs.webkit.org/show_bug.cgi?id=153522
<rdar://problem/24357822>

Reviewed by Benjamin Poulain.

Source/WebCore:

window.atob() should ignore spaces in input as per:

Previously, WebKit would throw an exception and it was the only browser
to do so. Firefox and Chrome behavior according to the specification.

This was causing us to fail 10 checks in the following W3C HTML test:
http://w3c-test.org/html/webappapis/atob/base64.html

No new tests, updated existing test.

  • page/DOMWindow.cpp:

(WebCore::DOMWindow::atob):

  • page/Page.cpp:

(WebCore::Page::userStyleSheetLocationChanged):

  • platform/network/DataURL.cpp:

(WebCore::handleDataURL):

  • platform/network/DataURLDecoder.cpp:

(WebCore::DataURLDecoder::decodeBase64):

Source/WebKit/mac:

  • WebCoreSupport/WebInspectorClient.mm:

(WebInspectorFrontendClient::save):

Source/WebKit2:

  • UIProcess/mac/WebInspectorProxyMac.mm:

(WebKit::WebInspectorProxy::platformSave):

Source/WTF:

Turn Base64DecodePolicy enum into flags so that the caller can indicate
to both validate padding AND ignore spaces.

Also make sure that the output Vector size is properly shrunk when
spaces are ignored.

  • wtf/text/Base64.cpp:

(WTF::base64DecodeInternal):
(WTF::base64Decode):
(WTF::base64URLDecode):

  • wtf/text/Base64.h:

LayoutTests:

Update window.atob() test to cover cases with spaces in
input.

  • fast/dom/Window/atob-btoa-expected.txt:
  • fast/dom/Window/atob-btoa.html:
Location:
trunk
Files:
15 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r195689 r195694  
     12016-01-27  Chris Dumez  <cdumez@apple.com>
     2
     3        window.atob() should ignore spaces in input
     4        https://bugs.webkit.org/show_bug.cgi?id=153522
     5        <rdar://problem/24357822>
     6
     7        Reviewed by Benjamin Poulain.
     8
     9        Update window.atob() test to cover cases with spaces in
     10        input.
     11
     12        * fast/dom/Window/atob-btoa-expected.txt:
     13        * fast/dom/Window/atob-btoa.html:
     14
    1152016-01-27  Brady Eidson  <beidson@apple.com>
    216
  • trunk/LayoutTests/fast/dom/Window/atob-btoa-expected.txt

    r153904 r195694  
    2727PASS window.atob(null) is "žée"
    2828PASS window.atob(undefined) threw exception Error: InvalidCharacterError: DOM Exception 5.
    29 PASS window.atob(" YQ==") threw exception Error: InvalidCharacterError: DOM Exception 5.
    30 PASS window.atob("YQ==\u000a") threw exception Error: InvalidCharacterError: DOM Exception 5.
     29PASS window.atob(" YQ==") is "a"
     30PASS window.atob("YQ==\u000a") is "a"
     31PASS window.atob("ab\tcd") is "i·
     32"
     33PASS window.atob("ab\ncd") is "i·
     34"
     35PASS window.atob("ab\fcd") is "i·
     36"
     37PASS window.atob("ab cd") is "i·
     38"
     39PASS window.atob("ab\t\n\f\r cd") is "i·
     40"
     41PASS window.atob(" \t\n\f\r ab\t\n\f\r cd\t\n\f\r ") is "i·
     42"
     43PASS window.atob("ab\t\n\f\r =\t\n\f\r =\t\n\f\r ") is "i"
     44PASS window.atob("            ") is ""
     45PASS window.atob(" abcd===") threw exception Error: InvalidCharacterError: DOM Exception 5.
     46PASS window.atob("abcd=== ") threw exception Error: InvalidCharacterError: DOM Exception 5.
     47PASS window.atob("abcd ===") threw exception Error: InvalidCharacterError: DOM Exception 5.
    3148PASS window.atob("6ek=") is "éé"
    3249PASS window.atob("6ek") is "éé"
  • trunk/LayoutTests/fast/dom/Window/atob-btoa.html

    r155265 r195694  
    3737shouldBe('window.atob(null)', '"\x9Eée"'); // Gets converted to "null" string.
    3838shouldThrow('window.atob(undefined)');
    39 shouldThrow('window.atob(" YQ==")');
    40 shouldThrow('window.atob("YQ==\\u000a")');
     39shouldBe('window.atob(" YQ==")', '"a"');
     40shouldBe('window.atob("YQ==\\u000a")', '"a"');
     41shouldBe('window.atob("ab\\tcd")', '"i·\x1d"');
     42shouldBe('window.atob("ab\\ncd")', '"i·\x1d"');
     43shouldBe('window.atob("ab\\fcd")', '"i·\x1d"');
     44shouldBe('window.atob("ab cd")', '"i·\x1d"');
     45shouldBe('window.atob("ab\\t\\n\\f\\r cd")', '"i·\x1d"');
     46shouldBe('window.atob(" \\t\\n\\f\\r ab\\t\\n\\f\\r cd\\t\\n\\f\\r ")', '"i·\x1d"');
     47shouldBe('window.atob("ab\\t\\n\\f\\r =\\t\\n\\f\\r =\\t\\n\\f\\r ")', '"i"');
     48shouldBe('window.atob("            ")', '""');
     49shouldThrow('window.atob(" abcd===")');
     50shouldThrow('window.atob("abcd=== ")');
     51shouldThrow('window.atob("abcd ===")');
    4152shouldBe('window.atob("6ek=")', '"éé"');
    4253shouldBe('window.atob("6ek")', '"éé"');
  • trunk/Source/WTF/ChangeLog

    r195675 r195694  
     12016-01-27  Chris Dumez  <cdumez@apple.com>
     2
     3        window.atob() should ignore spaces in input
     4        https://bugs.webkit.org/show_bug.cgi?id=153522
     5        <rdar://problem/24357822>
     6
     7        Reviewed by Benjamin Poulain.
     8
     9        Turn Base64DecodePolicy enum into flags so that the caller can indicate
     10        to both validate padding AND ignore spaces.
     11
     12        Also make sure that the output Vector size is properly shrunk when
     13        spaces are ignored.
     14
     15        * wtf/text/Base64.cpp:
     16        (WTF::base64DecodeInternal):
     17        (WTF::base64Decode):
     18        (WTF::base64URLDecode):
     19        * wtf/text/Base64.h:
     20
    1212016-01-27  Alexey Proskuryakov  <ap@apple.com>
    222
  • trunk/Source/WTF/wtf/text/Base64.cpp

    r165792 r195694  
    22   Copyright (C) 2000-2001 Dawit Alemayehu <adawit@kde.org>
    33   Copyright (C) 2006 Alexey Proskuryakov <ap@webkit.org>
    4    Copyright (C) 2007, 2008, 2013 Apple Inc. All rights reserved.
     4   Copyright (C) 2007, 2008, 2013, 2016 Apple Inc. All rights reserved.
    55   Copyright (C) 2010 Patrick Gansterer <paroga@paroga.com>
    66
     
    183183
    184184template<typename T>
    185 static inline bool base64DecodeInternal(const T* data, unsigned length, Vector<char>& out, Base64DecodePolicy policy, const char (&decodeMap)[128])
     185static inline bool base64DecodeInternal(const T* data, unsigned length, Vector<char>& out, unsigned options, const char (&decodeMap)[128])
    186186{
    187187    out.clear();
     
    193193    unsigned equalsSignCount = 0;
    194194    unsigned outLength = 0;
     195    bool hadError = false;
    195196    for (unsigned idx = 0; idx < length; ++idx) {
    196197        unsigned ch = data[idx];
    197198        if (ch == '=') {
    198199            ++equalsSignCount;
    199             // There should be no padding if length is a multiple of 4, and there
    200             // should never be more than 2 padding characters.
    201             if (policy == Base64FailOnInvalidCharacterOrExcessPadding && (length % 4 || equalsSignCount > 2))
    202                 return false;
     200            // There should never be more than 2 padding characters.
     201            if (options & Base64ValidatePadding && equalsSignCount > 2) {
     202                hadError = true;
     203                break;
     204            }
    203205        } else {
    204206            char decodedCharacter = ch < WTF_ARRAY_LENGTH(decodeMap) ? decodeMap[ch] : nonAlphabet;
    205207            if (decodedCharacter != nonAlphabet) {
    206                 if (equalsSignCount)
    207                     return false;
    208                 out[outLength] = decodedCharacter;
    209                 ++outLength;
    210             } else if (policy == Base64FailOnInvalidCharacterOrExcessPadding || policy == Base64FailOnInvalidCharacter || (policy == Base64IgnoreWhitespace && !isSpaceOrNewline(ch)))
    211                 return false;
     208                if (equalsSignCount) {
     209                    hadError = true;
     210                    break;
     211                }
     212                out[outLength++] = decodedCharacter;
     213            } else if (!(options & Base64IgnoreSpacesAndNewLines) || !isSpaceOrNewline(ch)) {
     214                hadError = true;
     215                break;
     216            }
    212217        }
    213218    }
     219
     220    // Make sure we shrink back the Vector before returning. outLength may be shorter than expected
     221    // in case of error or in case of ignored spaces.
     222    if (outLength < out.size())
     223        out.shrink(outLength);
     224
     225    if (hadError)
     226        return false;
    214227
    215228    if (!outLength)
    216229        return !equalsSignCount;
     230
     231    // The should be no padding if length is a multiple of 4.
     232    // We use (outLength + equalsSignCount) instead of length because we don't want to account for ignored characters (i.e. spaces).
     233    if (options & Base64ValidatePadding && equalsSignCount && (outLength + equalsSignCount) % 4)
     234        return false;
    217235
    218236    // Valid data is (n * 4 + [0,2,3]) characters long.
     
    249267}
    250268
    251 bool base64Decode(const String& in, SignedOrUnsignedCharVectorAdapter out, Base64DecodePolicy policy)
     269bool base64Decode(const String& in, SignedOrUnsignedCharVectorAdapter out, unsigned options)
    252270{
    253271    unsigned length = in.length();
    254272    if (!length || in.is8Bit())
    255         return base64DecodeInternal(in.characters8(), length, out, policy, base64DecMap);
    256     return base64DecodeInternal(in.characters16(), length, out, policy, base64DecMap);
    257 }
    258 
    259 bool base64Decode(const Vector<char>& in, SignedOrUnsignedCharVectorAdapter out, Base64DecodePolicy policy)
     273        return base64DecodeInternal(in.characters8(), length, out, options, base64DecMap);
     274    return base64DecodeInternal(in.characters16(), length, out, options, base64DecMap);
     275}
     276
     277bool base64Decode(const Vector<char>& in, SignedOrUnsignedCharVectorAdapter out, unsigned options)
    260278{
    261279    out.clear();
     
    265283        return false;
    266284
    267     return base64DecodeInternal(reinterpret_cast<const LChar*>(in.data()), in.size(), out, policy, base64DecMap);
    268 }
    269 
    270 bool base64Decode(const char* data, unsigned len, SignedOrUnsignedCharVectorAdapter out, Base64DecodePolicy policy)
    271 {
    272     return base64DecodeInternal(reinterpret_cast<const LChar*>(data), len, out, policy, base64DecMap);
     285    return base64DecodeInternal(reinterpret_cast<const LChar*>(in.data()), in.size(), out, options, base64DecMap);
     286}
     287
     288bool base64Decode(const char* data, unsigned len, SignedOrUnsignedCharVectorAdapter out, unsigned options)
     289{
     290    return base64DecodeInternal(reinterpret_cast<const LChar*>(data), len, out, options, base64DecMap);
    273291}
    274292
     
    277295    unsigned length = in.length();
    278296    if (!length || in.is8Bit())
    279         return base64DecodeInternal(in.characters8(), length, out, Base64FailOnInvalidCharacter, base64URLDecMap);
    280     return base64DecodeInternal(in.characters16(), length, out, Base64FailOnInvalidCharacter, base64URLDecMap);
     297        return base64DecodeInternal(in.characters8(), length, out, Base64Default, base64URLDecMap);
     298    return base64DecodeInternal(in.characters16(), length, out, Base64Default, base64URLDecMap);
    281299}
    282300
     
    289307        return false;
    290308
    291     return base64DecodeInternal(reinterpret_cast<const LChar*>(in.data()), in.size(), out, Base64FailOnInvalidCharacter, base64URLDecMap);
     309    return base64DecodeInternal(reinterpret_cast<const LChar*>(in.data()), in.size(), out, Base64Default, base64URLDecMap);
    292310}
    293311
    294312bool base64URLDecode(const char* data, unsigned len, SignedOrUnsignedCharVectorAdapter out)
    295313{
    296     return base64DecodeInternal(reinterpret_cast<const LChar*>(data), len, out, Base64FailOnInvalidCharacter, base64URLDecMap);
     314    return base64DecodeInternal(reinterpret_cast<const LChar*>(data), len, out, Base64Default, base64URLDecMap);
    297315}
    298316
  • trunk/Source/WTF/wtf/text/Base64.h

    r171696 r195694  
    22 * Copyright (C) 2006 Alexey Proskuryakov <ap@webkit.org>
    33 * Copyright (C) 2010 Patrick Gansterer <paroga@paroga.com>
    4  * Copyright (C) 2013 Apple Inc. All rights reserved.
     4 * Copyright (C) 2013, 2016 Apple Inc. All rights reserved.
    55 *
    66 * Redistribution and use in source and binary forms, with or without
     
    4141};
    4242
    43 enum Base64DecodePolicy {
    44     Base64FailOnInvalidCharacterOrExcessPadding,
    45     Base64FailOnInvalidCharacter,
    46     Base64IgnoreWhitespace,
    47     Base64IgnoreInvalidCharacters
     43enum Base64DecodeOptions {
     44    Base64Default = 0,
     45    Base64ValidatePadding = 1 << 0,
     46    Base64IgnoreSpacesAndNewLines = 1 << 1,
    4847};
    4948
     
    8685String base64Encode(const CString&, Base64EncodePolicy = Base64DoNotInsertLFs);
    8786
    88 WTF_EXPORT_PRIVATE bool base64Decode(const String&, SignedOrUnsignedCharVectorAdapter, Base64DecodePolicy = Base64FailOnInvalidCharacter);
    89 WTF_EXPORT_PRIVATE bool base64Decode(const Vector<char>&, SignedOrUnsignedCharVectorAdapter, Base64DecodePolicy = Base64FailOnInvalidCharacter);
    90 WTF_EXPORT_PRIVATE bool base64Decode(const char*, unsigned, SignedOrUnsignedCharVectorAdapter, Base64DecodePolicy = Base64FailOnInvalidCharacter);
     87WTF_EXPORT_PRIVATE bool base64Decode(const String&, SignedOrUnsignedCharVectorAdapter, unsigned options = Base64Default);
     88WTF_EXPORT_PRIVATE bool base64Decode(const Vector<char>&, SignedOrUnsignedCharVectorAdapter, unsigned options = Base64Default);
     89WTF_EXPORT_PRIVATE bool base64Decode(const char*, unsigned, SignedOrUnsignedCharVectorAdapter, unsigned options = Base64Default);
    9190
    9291inline void base64Encode(ConstSignedOrUnsignedCharVectorAdapter in, Vector<char>& out, Base64EncodePolicy policy)
     
    152151using WTF::Base64DoNotInsertLFs;
    153152using WTF::Base64InsertLFs;
    154 using WTF::Base64DecodePolicy;
    155 using WTF::Base64FailOnInvalidCharacterOrExcessPadding;
    156 using WTF::Base64FailOnInvalidCharacter;
    157 using WTF::Base64IgnoreWhitespace;
    158 using WTF::Base64IgnoreInvalidCharacters;
     153using WTF::Base64ValidatePadding;
     154using WTF::Base64IgnoreSpacesAndNewLines;
    159155using WTF::base64Encode;
    160156using WTF::base64Decode;
  • trunk/Source/WebCore/ChangeLog

    r195693 r195694  
     12016-01-27  Chris Dumez  <cdumez@apple.com>
     2
     3        window.atob() should ignore spaces in input
     4        https://bugs.webkit.org/show_bug.cgi?id=153522
     5        <rdar://problem/24357822>
     6
     7        Reviewed by Benjamin Poulain.
     8
     9        window.atob() should ignore spaces in input as per:
     10        - https://html.spec.whatwg.org/#dom-windowbase64-atob (Step 3)
     11
     12        Previously, WebKit would throw an exception and it was the only browser
     13        to do so. Firefox and Chrome behavior according to the specification.
     14
     15        This was causing us to fail 10 checks in the following W3C HTML test:
     16        http://w3c-test.org/html/webappapis/atob/base64.html
     17
     18        No new tests, updated existing test.
     19
     20        * page/DOMWindow.cpp:
     21        (WebCore::DOMWindow::atob):
     22        * page/Page.cpp:
     23        (WebCore::Page::userStyleSheetLocationChanged):
     24        * platform/network/DataURL.cpp:
     25        (WebCore::handleDataURL):
     26        * platform/network/DataURLDecoder.cpp:
     27        (WebCore::DataURLDecoder::decodeBase64):
     28
    1292016-01-27  Ada Chan  <adachan@apple.com>
    230
  • trunk/Source/WebCore/page/DOMWindow.cpp

    r194819 r195694  
    11611161
    11621162    Vector<char> out;
    1163     if (!base64Decode(encodedString, out, Base64FailOnInvalidCharacterOrExcessPadding)) {
     1163    if (!base64Decode(encodedString, out, Base64ValidatePadding | Base64IgnoreSpacesAndNewLines)) {
    11641164        ec = INVALID_CHARACTER_ERR;
    11651165        return String();
  • trunk/Source/WebCore/page/Page.cpp

    r195644 r195694  
    10331033
    10341034        Vector<char> styleSheetAsUTF8;
    1035         if (base64Decode(decodeURLEscapeSequences(url.string().substring(35)), styleSheetAsUTF8, Base64IgnoreWhitespace))
     1035        if (base64Decode(decodeURLEscapeSequences(url.string().substring(35)), styleSheetAsUTF8, Base64IgnoreSpacesAndNewLines))
    10361036            m_userStyleSheet = String::fromUTF8(styleSheetAsUTF8.data(), styleSheetAsUTF8.size());
    10371037    }
  • trunk/Source/WebCore/platform/network/DataURL.cpp

    r165848 r195694  
    7777
    7878        Vector<char> out;
    79         if (base64Decode(data, out, Base64IgnoreWhitespace) && out.size() > 0) {
     79        if (base64Decode(data, out, Base64IgnoreSpacesAndNewLines) && out.size() > 0) {
    8080            response.setExpectedContentLength(out.size());
    8181            handle->client()->didReceiveData(handle, out.data(), out.size(), 0);
  • trunk/Source/WebCore/platform/network/DataURLDecoder.cpp

    r194496 r195694  
    145145        // Didn't work, try unescaping and decoding as base64.
    146146        auto unescapedString = decodeURLEscapeSequences(task.encodedData.toStringWithoutCopying());
    147         if (!base64Decode(unescapedString, buffer, Base64IgnoreWhitespace))
     147        if (!base64Decode(unescapedString, buffer, Base64IgnoreSpacesAndNewLines))
    148148            return;
    149149    }
  • trunk/Source/WebKit/mac/ChangeLog

    r195675 r195694  
     12016-01-27  Chris Dumez  <cdumez@apple.com>
     2
     3        window.atob() should ignore spaces in input
     4        https://bugs.webkit.org/show_bug.cgi?id=153522
     5        <rdar://problem/24357822>
     6
     7        Reviewed by Benjamin Poulain.
     8
     9        * WebCoreSupport/WebInspectorClient.mm:
     10        (WebInspectorFrontendClient::save):
     11
    1122016-01-27  Alexey Proskuryakov  <ap@apple.com>
    213
  • trunk/Source/WebKit/mac/WebCoreSupport/WebInspectorClient.mm

    r194496 r195694  
    311311        if (base64Encoded) {
    312312            Vector<char> out;
    313             if (!base64Decode(contentCopy, out, Base64FailOnInvalidCharacterOrExcessPadding))
     313            if (!base64Decode(contentCopy, out, Base64ValidatePadding))
    314314                return;
    315315            RetainPtr<NSData> dataContent = adoptNS([[NSData alloc] initWithBytes:out.data() length:out.size()]);
  • trunk/Source/WebKit2/ChangeLog

    r195686 r195694  
     12016-01-27  Chris Dumez  <cdumez@apple.com>
     2
     3        window.atob() should ignore spaces in input
     4        https://bugs.webkit.org/show_bug.cgi?id=153522
     5        <rdar://problem/24357822>
     6
     7        Reviewed by Benjamin Poulain.
     8
     9        * UIProcess/mac/WebInspectorProxyMac.mm:
     10        (WebKit::WebInspectorProxy::platformSave):
     11
    1122016-01-27  Ryosuke Niwa  <rniwa@webkit.org>
    213
  • trunk/Source/WebKit2/UIProcess/mac/WebInspectorProxyMac.mm

    r194322 r195694  
    569569        if (base64Encoded) {
    570570            Vector<char> out;
    571             if (!base64Decode(contentCopy, out, Base64FailOnInvalidCharacterOrExcessPadding))
     571            if (!base64Decode(contentCopy, out, Base64ValidatePadding))
    572572                return;
    573573            RetainPtr<NSData> dataContent = adoptNS([[NSData alloc] initWithBytes:out.data() length:out.size()]);
Note: See TracChangeset for help on using the changeset viewer.