Changeset 188820 in webkit


Ignore:
Timestamp:
Aug 22, 2015 2:57:23 AM (9 years ago)
Author:
Antti Koivisto
Message:

Decode data URLs in web process
https://bugs.webkit.org/show_bug.cgi?id=148128

Reviewed by Darin Adler.

Source/WebCore:

We currenly send data URLs to networking layer for decoding. This involves a long and slow roundtrip through IPC and API layers.

  • WebCore.xcodeproj/project.pbxproj:
  • loader/ResourceLoadScheduler.cpp:

(WebCore::ResourceLoadScheduler::maybeLoadQuickLookResource): Deleted.

Remove this awkward interface for WebKit2.

  • loader/ResourceLoadScheduler.h:
  • loader/ResourceLoader.cpp:

(WebCore::ResourceLoader::start):
(WebCore::ResourceLoader::loadDataURL):

Load using DataURLDecoder.

  • loader/ResourceLoader.h:

Make start() public and export it so it can be called directly from WebKit2.

  • platform/network/DataURLDecoder.cpp: Added.

(WebCore::DataURLDecoder::decodeQueue):
(WebCore::DataURLDecoder::DecodeTask::DecodeTask):
(WebCore::DataURLDecoder::createDecodeTask):

Parse data URL metadata and initialize the decode task.

(WebCore::DataURLDecoder::decodeBase64):
(WebCore::DataURLDecoder::decodeEscaped):
(WebCore::DataURLDecoder::decode):

Asynchronously decode in a concurrent distpatch queue.

  • platform/network/DataURLDecoder.h: Added.
  • platform/network/ios/QuickLook.h:
  • platform/text/DecodeEscapeSequences.h:

(WebCore::URLEscapeSequence::findEndOfRun):
(WebCore::URLEscapeSequence::decodeRun):

Factor buffer generation to a function.

(WebCore::decodeEscapeSequences):
(WebCore::decodeURLEscapeSequencesAsData):

Add decode function that produces bytes instead of a String.

Source/WebKit2:

  • WebProcess/Network/WebResourceLoadScheduler.cpp:

(WebKit::WebResourceLoadScheduler::scheduleLoad):

Don't send data: loads to the network process, handle them locally.

(WebKit::WebResourceLoadScheduler::startLocalLoad):

Call ResourceLoder::start() directly.

Location:
trunk/Source
Files:
2 added
13 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/CMakeLists.txt

    r188809 r188820  
    22542254    platform/network/DNSResolveQueue.cpp
    22552255    platform/network/DataURL.cpp
     2256    platform/network/DataURLDecoder.cpp
    22562257    platform/network/FormData.cpp
    22572258    platform/network/FormDataBuilder.cpp
  • trunk/Source/WebCore/ChangeLog

    r188810 r188820  
     12015-08-22  Antti Koivisto  <antti@apple.com>
     2
     3        Decode data URLs in web process
     4        https://bugs.webkit.org/show_bug.cgi?id=148128
     5
     6        Reviewed by Darin Adler.
     7
     8        We currenly send data URLs to networking layer for decoding. This involves a long and slow roundtrip through IPC and API layers.
     9
     10        * WebCore.xcodeproj/project.pbxproj:
     11        * loader/ResourceLoadScheduler.cpp:
     12        (WebCore::ResourceLoadScheduler::maybeLoadQuickLookResource): Deleted.
     13
     14            Remove this awkward interface for WebKit2.
     15
     16        * loader/ResourceLoadScheduler.h:
     17        * loader/ResourceLoader.cpp:
     18        (WebCore::ResourceLoader::start):
     19        (WebCore::ResourceLoader::loadDataURL):
     20
     21            Load using DataURLDecoder.
     22
     23        * loader/ResourceLoader.h:
     24
     25            Make start() public and export it so it can be called directly from WebKit2.
     26
     27        * platform/network/DataURLDecoder.cpp: Added.
     28        (WebCore::DataURLDecoder::decodeQueue):
     29        (WebCore::DataURLDecoder::DecodeTask::DecodeTask):
     30        (WebCore::DataURLDecoder::createDecodeTask):
     31
     32            Parse data URL metadata and initialize the decode task.
     33
     34        (WebCore::DataURLDecoder::decodeBase64):
     35        (WebCore::DataURLDecoder::decodeEscaped):
     36        (WebCore::DataURLDecoder::decode):
     37
     38            Asynchronously decode in a concurrent distpatch queue.
     39
     40        * platform/network/DataURLDecoder.h: Added.
     41        * platform/network/ios/QuickLook.h:
     42        * platform/text/DecodeEscapeSequences.h:
     43        (WebCore::URLEscapeSequence::findEndOfRun):
     44        (WebCore::URLEscapeSequence::decodeRun):
     45
     46            Factor buffer generation to a function.
     47
     48        (WebCore::decodeEscapeSequences):
     49        (WebCore::decodeURLEscapeSequencesAsData):
     50
     51            Add decode function that produces bytes instead of a String.
     52
    1532015-08-21  Commit Queue  <commit-queue@webkit.org>
    254
  • trunk/Source/WebCore/WebCore.vcxproj/WebCore.vcxproj

    r188809 r188820  
    88218821    <ClCompile Include="..\platform\network\CredentialStorage.cpp" />
    88228822    <ClCompile Include="..\platform\network\DataURL.cpp" />
     8823    <ClCompile Include="..\platform\network\DataURLDecoder.cpp" />
    88238824    <ClCompile Include="..\platform\network\DNSResolveQueue.cpp" />
    88248825    <ClCompile Include="..\platform\network\FormData.cpp" />
     
    2133221333    <ClInclude Include="..\platform\network\CredentialStorage.h" />
    2133321334    <ClInclude Include="..\platform\network\DataURL.h" />
     21335    <ClInclude Include="..\platform\network\DataURLDecoder.h" />
    2133421336    <ClInclude Include="..\platform\network\DNSResolveQueue.h" />
    2133521337    <ClInclude Include="..\platform\network\FormData.h" />
  • trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj

    r188809 r188820  
    63736373                E49BD9FA131FD2ED003C56F0 /* CSSValuePool.h in Headers */ = {isa = PBXBuildFile; fileRef = E49BD9F9131FD2ED003C56F0 /* CSSValuePool.h */; };
    63746374                E49BDA0B131FD3E5003C56F0 /* CSSValuePool.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E49BDA0A131FD3E5003C56F0 /* CSSValuePool.cpp */; };
     6375                E4A007831B820EC8002C5A6E /* DataURLDecoder.h in Headers */ = {isa = PBXBuildFile; fileRef = E4A007821B820EC8002C5A6E /* DataURLDecoder.h */; };
     6376                E4A007851B820ED3002C5A6E /* DataURLDecoder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E4A007841B820ED3002C5A6E /* DataURLDecoder.cpp */; };
    63756377                E4AE7C1617D1BB950009FB31 /* ElementIterator.h in Headers */ = {isa = PBXBuildFile; fileRef = E4AE7C1517D1BB950009FB31 /* ElementIterator.h */; settings = {ATTRIBUTES = (Private, ); }; };
    63766378                E4AE7C1A17D232350009FB31 /* ElementAncestorIterator.h in Headers */ = {isa = PBXBuildFile; fileRef = E4AE7C1917D232350009FB31 /* ElementAncestorIterator.h */; settings = {ATTRIBUTES = (Private, ); }; };
     
    1408214084                E49BD9F9131FD2ED003C56F0 /* CSSValuePool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSSValuePool.h; sourceTree = "<group>"; };
    1408314085                E49BDA0A131FD3E5003C56F0 /* CSSValuePool.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CSSValuePool.cpp; sourceTree = "<group>"; };
     14086                E4A007821B820EC8002C5A6E /* DataURLDecoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DataURLDecoder.h; sourceTree = "<group>"; };
     14087                E4A007841B820ED3002C5A6E /* DataURLDecoder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DataURLDecoder.cpp; sourceTree = "<group>"; };
    1408414088                E4AE7C1517D1BB950009FB31 /* ElementIterator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ElementIterator.h; sourceTree = "<group>"; };
    1408514089                E4AE7C1917D232350009FB31 /* ElementAncestorIterator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ElementAncestorIterator.h; sourceTree = "<group>"; };
     
    1688016884                                51A052321058774F00CC9E95 /* CredentialStorage.cpp */,
    1688116885                                51A052311058774F00CC9E95 /* CredentialStorage.h */,
     16886                                E4A007841B820ED3002C5A6E /* DataURLDecoder.cpp */,
     16887                                E4A007821B820EC8002C5A6E /* DataURLDecoder.h */,
    1688216888                                B2F34FE50E82F81400F627CD /* DNS.h */,
    1688316889                                7C60128060078BB70E367A95 /* DNSResolveQueue.cpp */,
     
    2607526081                                CD3A495F17A9D01B00274E42 /* MediaSource.h in Headers */,
    2607626082                                CD641EB31818F5ED00EE4C41 /* MediaSourcePrivate.h in Headers */,
     26083                                E4A007831B820EC8002C5A6E /* DataURLDecoder.h in Headers */,
    2607726084                                CDC8B5A7180474F70016E685 /* MediaSourcePrivateAVFObjC.h in Headers */,
    2607826085                                CDDC1E7A18A952F30027A9D4 /* MediaSourcePrivateClient.h in Headers */,
     
    2840928416                                31C0FF4A0E4CEFDD007D6FE5 /* DOMWebKitAnimationEvent.mm in Sources */,
    2841028417                                3106037A143281CD00ABF4BA /* DOMWebKitCSSFilterValue.mm in Sources */,
     28418                                E4A007851B820ED3002C5A6E /* DataURLDecoder.cpp in Sources */,
    2841128419                                498391510F1E76B400C23782 /* DOMWebKitCSSMatrix.mm in Sources */,
    2841228420                                8AD0A59714C88358000D83C5 /* DOMWebKitCSSRegionRule.mm in Sources */,
  • trunk/Source/WebCore/loader/ResourceLoadScheduler.cpp

    r187002 r188820  
    196196}
    197197
    198 #if USE(QUICK_LOOK)
    199 bool ResourceLoadScheduler::maybeLoadQuickLookResource(ResourceLoader& loader)
    200 {
    201     if (!loader.request().url().protocolIs(QLPreviewProtocol()))
    202         return false;
    203 
    204     loader.start();
    205     return true;
    206 }
    207 #endif
    208 
    209198void ResourceLoadScheduler::remove(ResourceLoader* resourceLoader)
    210199{
  • trunk/Source/WebCore/loader/ResourceLoadScheduler.h

    r187002 r188820  
    7777    WEBCORE_EXPORT virtual ~ResourceLoadScheduler();
    7878
    79 #if USE(QUICK_LOOK)
    80     WEBCORE_EXPORT bool maybeLoadQuickLookResource(ResourceLoader&);
    81 #endif
    82 
    8379private:
    8480    void scheduleLoad(ResourceLoader*);
  • trunk/Source/WebCore/loader/ResourceLoader.cpp

    r188211 r188820  
    3333#include "ApplicationCacheHost.h"
    3434#include "AuthenticationChallenge.h"
     35#include "DataURLDecoder.h"
    3536#include "DiagnosticLoggingClient.h"
    3637#include "DiagnosticLoggingKeys.h"
     
    203204    }
    204205
    205     if (!m_reachedTerminalState) {
    206         FrameLoader& loader = m_request.url().protocolIsData() ? dataProtocolFrameLoader() : *frameLoader();
    207         m_handle = ResourceHandle::create(loader.networkingContext(), m_request, this, m_defersLoading, m_options.sniffContent() == SniffContent);
    208     }
     206    if (m_reachedTerminalState)
     207        return;
     208
     209    if (m_request.url().protocolIsData()) {
     210        loadDataURL();
     211        return;
     212    }
     213
     214    m_handle = ResourceHandle::create(frameLoader()->networkingContext(), m_request, this, m_defersLoading, m_options.sniffContent() == SniffContent);
    209215}
    210216
     
    228234        return nullptr;
    229235    return &m_frame->loader();
     236}
     237
     238void ResourceLoader::loadDataURL()
     239{
     240    auto url = m_request.url();
     241    ASSERT(url.protocolIsData());
     242
     243    RefPtr<ResourceLoader> loader(this);
     244    DataURLDecoder::decode(url, [loader, url] (Optional<DataURLDecoder::Result> decodeResult) {
     245        if (loader->reachedTerminalState())
     246            return;
     247        if (!decodeResult) {
     248            loader->didFail(ResourceError(errorDomainWebKitInternal, 0, url.string(), "Data URL decoding failed"));
     249            return;
     250        }
     251        auto& result = decodeResult.value();
     252        auto dataSize = result.data->size();
     253
     254        ResourceResponse dataResponse { url, result.mimeType, dataSize, result.charset };
     255        loader->didReceiveResponse(dataResponse);
     256
     257        if (!loader->reachedTerminalState() && dataSize)
     258            loader->didReceiveBuffer(result.data.get(), dataSize, DataPayloadWholeResource);
     259
     260        if (!loader->reachedTerminalState())
     261            loader->didFinishLoading(currentTime());
     262    });
    230263}
    231264
  • trunk/Source/WebCore/loader/ResourceLoader.h

    r187886 r188820  
    8181    DocumentLoader* documentLoader() const { return m_documentLoader.get(); }
    8282    const ResourceRequest& originalRequest() const { return m_originalRequest; }
    83    
     83
     84    WEBCORE_EXPORT void start();
    8485    WEBCORE_EXPORT void cancel(const ResourceError&);
    8586    WEBCORE_EXPORT ResourceError cancelledError();
     
    149150    ResourceLoader(Frame*, ResourceLoaderOptions);
    150151
    151     friend class ResourceLoadScheduler; // for access to start()
    152     // start() actually sends the load to the network (unless the load is being
    153     // deferred) and should only be called by ResourceLoadScheduler or setDefersLoading().
    154     void start();
    155 
    156152    void didFinishLoadingOnePart(double finishTime);
    157153    void cleanupForError(const ResourceError&);
     
    182178
    183179    void addDataOrBuffer(const char*, unsigned, SharedBuffer*, DataPayloadType);
     180    void loadDataURL();
    184181
    185182    // ResourceHandleClient
  • trunk/Source/WebCore/platform/network/ios/QuickLook.h

    r183598 r188820  
    7373const URL safeQLURLForDocumentURLAndResourceURL(const URL& documentURL, const String& resourceURL);
    7474
    75 const char* QLPreviewProtocol();
     75WEBCORE_EXPORT const char* QLPreviewProtocol();
    7676
    7777WEBCORE_EXPORT NSString *createTemporaryFileForQuickLook(NSString *fileName);
  • trunk/Source/WebCore/platform/text/DecodeEscapeSequences.h

    r165848 r188820  
    4141struct Unicode16BitEscapeSequence {
    4242    enum { sequenceSize = 6 }; // e.g. %u26C4
    43     static size_t findInString(const String& string, size_t startPosition) { return string.find("%u", startPosition); }
    44     static size_t findEndOfRun(const String& string, size_t startPosition, size_t endPosition)
     43    static size_t findInString(StringView string, size_t startPosition) { return string.find(StringView("%u"), startPosition); }
     44    static size_t findEndOfRun(StringView string, size_t startPosition, size_t endPosition)
    4545    {
    4646        size_t runEnd = startPosition;
     
    7272struct URLEscapeSequence {
    7373    enum { sequenceSize = 3 }; // e.g. %41
    74     static size_t findInString(const String& string, size_t startPosition) { return string.find('%', startPosition); }
    75     static size_t findEndOfRun(const String& string, size_t startPosition, size_t endPosition)
     74    static size_t findInString(StringView string, size_t startPosition) { return string.find('%', startPosition); }
     75    static size_t findEndOfRun(StringView string, size_t startPosition, size_t endPosition)
    7676    {
    7777        // Make the simplifying assumption that supported encodings may have up to two unescaped characters
     
    9797        return runEnd;
    9898    }
    99     static String decodeRun(StringView run, const TextEncoding& encoding)
     99
     100    static Vector<char, 512> decodeRun(StringView run)
    100101    {
    101102        // For URL escape sequences, we know that findEndOfRun() has given us a run where every %-sign introduces
     
    114115        }
    115116        ASSERT(buffer.size() >= static_cast<size_t>(p - buffer.data())); // Prove buffer not overrun.
    116         return (encoding.isValid() ? encoding : UTF8Encoding()).decode(buffer.data(), p - buffer.data());
     117        buffer.shrink(p - buffer.data());
     118        return buffer;
     119    }
     120
     121    static String decodeRun(StringView run, const TextEncoding& encoding)
     122    {
     123        auto buffer = decodeRun(run);
     124        if (!encoding.isValid())
     125            return UTF8Encoding().decode(buffer.data(), buffer.size());
     126        return encoding.decode(buffer.data(), buffer.size());
    117127    }
    118128};
    119129
    120130template<typename EscapeSequence>
    121 String decodeEscapeSequences(const String& string, const TextEncoding& encoding)
     131String decodeEscapeSequences(StringView string, const TextEncoding& encoding)
    122132{
    123133    StringBuilder result;
     
    134144        }
    135145
    136         String decoded = EscapeSequence::decodeRun(StringView(string).substring(encodedRunPosition, encodedRunEnd - encodedRunPosition), encoding);
     146        String decoded = EscapeSequence::decodeRun(string.substring(encodedRunPosition, encodedRunEnd - encodedRunPosition), encoding);
    137147        if (decoded.isEmpty())
    138148            continue;
    139149
    140         result.append(string, decodedPosition, encodedRunPosition - decodedPosition);
     150        result.append(string.substring(decodedPosition, encodedRunPosition - decodedPosition));
    141151        result.append(decoded);
    142152        decodedPosition = encodedRunEnd;
    143153    }
    144     result.append(string, decodedPosition, length - decodedPosition);
     154    result.append(string.substring(decodedPosition, length - decodedPosition));
    145155    return result.toString();
     156}
     157
     158inline Vector<char> decodeURLEscapeSequencesAsData(StringView string, const TextEncoding& encoding)
     159{
     160    ASSERT(encoding.isValid());
     161
     162    Vector<char> result;
     163    size_t decodedPosition = 0;
     164    size_t searchPosition = 0;
     165    while (true) {
     166        size_t encodedRunPosition = URLEscapeSequence::findInString(string, searchPosition);
     167        size_t encodedRunEnd = 0;
     168        if (encodedRunPosition != notFound) {
     169            encodedRunEnd = URLEscapeSequence::findEndOfRun(string, encodedRunPosition, string.length());
     170            searchPosition = encodedRunEnd;
     171            if (encodedRunEnd == encodedRunPosition) {
     172                ++searchPosition;
     173                continue;
     174            }
     175        }
     176        // Strings are encoded as requested.
     177        auto stringFragment = string.substring(decodedPosition, encodedRunPosition - decodedPosition);
     178        auto encodedStringFragment = encoding.encode(stringFragment, URLEncodedEntitiesForUnencodables);
     179        result.append(encodedStringFragment.data(), encodedStringFragment.length());
     180
     181        if (encodedRunPosition == notFound)
     182            return result;
     183       
     184        // Bytes go through as-is.
     185        auto decodedEscapeSequence = URLEscapeSequence::decodeRun(string.substring(encodedRunPosition, encodedRunEnd - encodedRunPosition));
     186        ASSERT(!decodedEscapeSequence.isEmpty());
     187        result.appendVector(decodedEscapeSequence);
     188
     189        decodedPosition = encodedRunEnd;
     190    }
    146191}
    147192
  • trunk/Source/WebKit2/ChangeLog

    r188817 r188820  
     12015-08-22  Antti Koivisto  <antti@apple.com>
     2
     3        Decode data URLs in web process
     4        https://bugs.webkit.org/show_bug.cgi?id=148128
     5
     6        Reviewed by Darin Adler.
     7
     8        * WebProcess/Network/WebResourceLoadScheduler.cpp:
     9        (WebKit::WebResourceLoadScheduler::scheduleLoad):
     10
     11            Don't send data: loads to the network process, handle them locally.
     12
     13        (WebKit::WebResourceLoadScheduler::startLocalLoad):
     14
     15            Call ResourceLoder::start() directly.
     16
    1172015-08-21  Commit Queue  <commit-queue@webkit.org>
    218
  • trunk/Source/WebKit2/WebProcess/Network/WebResourceLoadScheduler.cpp

    r187002 r188820  
    142142    }
    143143
     144    if (resourceLoader->request().url().protocolIsData()) {
     145        LOG(NetworkScheduling, "(WebProcess) WebResourceLoadScheduler::scheduleLoad, url '%s' will be loaded as data.", resourceLoader->url().string().utf8().data());
     146        startLocalLoad(*resourceLoader);
     147        return;
     148    }
     149
    144150#if USE(QUICK_LOOK)
    145     if (maybeLoadQuickLookResource(*resourceLoader)) {
     151    if (resourceLoader->request().url().protocolIs(QLPreviewProtocol())) {
    146152        LOG(NetworkScheduling, "(WebProcess) WebResourceLoadScheduler::scheduleLoad, url '%s' will be handled as a QuickLook resource.", resourceLoader->url().string().utf8().data());
    147         m_webResourceLoaders.set(identifier, WebResourceLoader::create(resourceLoader));
     153        startLocalLoad(*resourceLoader);
    148154        return;
    149155    }
     
    204210}
    205211
     212void WebResourceLoadScheduler::startLocalLoad(WebCore::ResourceLoader& resourceLoader)
     213{
     214    resourceLoader.start();
     215    m_webResourceLoaders.set(resourceLoader.identifier(), WebResourceLoader::create(&resourceLoader));
     216}
     217
    206218void WebResourceLoadScheduler::remove(ResourceLoader* resourceLoader)
    207219{
  • trunk/Source/WebKit2/WebProcess/Network/WebResourceLoadScheduler.h

    r187002 r188820  
    6868    void scheduleInternallyFailedLoad(WebCore::ResourceLoader*);
    6969    void internallyFailedLoadTimerFired();
    70    
     70    void startLocalLoad(WebCore::ResourceLoader&);
     71
    7172    HashSet<RefPtr<WebCore::ResourceLoader>> m_internallyFailedResourceLoaders;
    7273    RunLoop::Timer<WebResourceLoadScheduler> m_internallyFailedLoadTimer;
Note: See TracChangeset for help on using the changeset viewer.