Changeset 222839 in webkit


Ignore:
Timestamp:
Oct 4, 2017 4:06:15 AM (7 years ago)
Author:
rniwa@webkit.org
Message:

Use blob URL when pasting RTFD instead of overriding DocumentLoader
https://bugs.webkit.org/show_bug.cgi?id=177801
<rdar://problem/34542270>

Reviewed by Wenson Hsieh.

Source/WebCore:

Before this patch, pasting RTFD resulted in images and other subresources in RTFD are being placed
into the document using WebKit fake URL, and DocumentLoader was overridden to return the appropriate
data upon resource requests. This is bad because there is no mechanism for websites to access its content.

Like r222119 and r208451, this patch fixes thie problem by using a blob URL instead of a WebKit fake URL.
This patch also adds a Blob::create variant which takes a SharedBuffer.

API Tests: PasteRTFD

  • editing/WebCorePasteboardFileReader.cpp:

(WebCore::WebCorePasteboardFileReader::readBuffer):

  • editing/cocoa/WebContentReaderCocoa.mm:

(WebCore::DeferredLoadingScope): Extracted out of createFragmentAndAddResources for clarity.
(WebCore::DeferredLoadingScope::DeferredLoadingScope):
(WebCore::DeferredLoadingScope::~DeferredLoadingScope):
(WebCore::createFragmentAndAddResources): Instead of adding resources to document loader, replace each
URL in the document by a blob URL.
(WebCore::WebContentReader::readImage):

  • editing/markup.cpp:

(WebCore::replaceSubresourceURLs): Added. A helper to replace each URL in the document fragment by a blob
URL created for each subresource. This won't work for iframes or srcset but that's okay for now since DOM
constructed from RTFD doesn't use either.

  • editing/markup.h:
  • fileapi/Blob.cpp:

(WebCore::Blob::Blob): Added a variant which takes a SharedBuffer.

  • fileapi/Blob.h:

(WebCore::Blob::create): Ditto.

Source/WebKit:

Fixed the assertion failure when RTFD content is empty.

  • UIProcess/Cocoa/WebPasteboardProxyCocoa.mm:

(WebKit::WebPasteboardProxy::getPasteboardBufferForType):

Tools:

Added a regression test for an assertion failure when pasting an empty RTFD as well as a test for pasting
RTFD with an image, which should result in an image element with a blob URL.

  • TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
  • TestWebKitAPI/Tests/WebKitCocoa/PasteImage.mm:
  • TestWebKitAPI/Tests/WebKitCocoa/PasteRTFD.mm:
  • TestWebKitAPI/Tests/WebKitCocoa/paste-rtfd.html:
Location:
trunk
Files:
2 added
13 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r222837 r222839  
     12017-10-04  Ryosuke Niwa  <rniwa@webkit.org>
     2
     3        Use blob URL when pasting RTFD instead of overriding DocumentLoader
     4        https://bugs.webkit.org/show_bug.cgi?id=177801
     5        <rdar://problem/34542270>
     6
     7        Reviewed by Wenson Hsieh.
     8
     9        Before this patch, pasting RTFD resulted in images and other subresources in RTFD are being placed
     10        into the document using WebKit fake URL, and DocumentLoader was overridden to return the appropriate
     11        data upon resource requests. This is bad because there is no mechanism for websites to access its content.
     12
     13        Like r222119 and r208451, this patch fixes thie problem by using a blob URL instead of a WebKit fake URL.
     14        This patch also adds a Blob::create variant which takes a SharedBuffer.
     15
     16        API Tests: PasteRTFD
     17
     18        * editing/WebCorePasteboardFileReader.cpp:
     19        (WebCore::WebCorePasteboardFileReader::readBuffer):
     20        * editing/cocoa/WebContentReaderCocoa.mm:
     21        (WebCore::DeferredLoadingScope): Extracted out of createFragmentAndAddResources for clarity.
     22        (WebCore::DeferredLoadingScope::DeferredLoadingScope):
     23        (WebCore::DeferredLoadingScope::~DeferredLoadingScope):
     24        (WebCore::createFragmentAndAddResources): Instead of adding resources to document loader, replace each
     25        URL in the document by a blob URL.
     26        (WebCore::WebContentReader::readImage):
     27        * editing/markup.cpp:
     28        (WebCore::replaceSubresourceURLs): Added. A helper to replace each URL in the document fragment by a blob
     29        URL created for each subresource. This won't work for iframes or srcset but that's okay for now since DOM
     30        constructed from RTFD doesn't use either.
     31        * editing/markup.h:
     32        * fileapi/Blob.cpp:
     33        (WebCore::Blob::Blob): Added a variant which takes a SharedBuffer.
     34        * fileapi/Blob.h:
     35        (WebCore::Blob::create): Ditto.
     36
    1372017-10-04  Michael Catanzaro  <mcatanzaro@igalia.com>
    238
  • trunk/Source/WebCore/Modules/fetch/FetchBodyOwner.cpp

    r222561 r222839  
    109109{
    110110    if (isBodyNullOrOpaque()) {
    111         promise->resolve<IDLInterface<Blob>>(Blob::create({ }, Blob::normalizedContentType(extractMIMETypeFromMediaType(m_contentType))));
     111        promise->resolve<IDLInterface<Blob>>(Blob::create(Vector<uint8_t> { }, Blob::normalizedContentType(extractMIMETypeFromMediaType(m_contentType))));
    112112        return;
    113113    }
  • trunk/Source/WebCore/editing/WebCorePasteboardFileReader.cpp

    r222699 r222839  
    4141void WebCorePasteboardFileReader::readBuffer(const String& filename, const String& type, Ref<SharedBuffer>&& buffer)
    4242{
    43     Vector<uint8_t> data;
    44     data.append(buffer->data(), buffer->size());
    45     files.append(File::create(Blob::create(WTFMove(data), type), filename));
     43    files.append(File::create(Blob::create(buffer.get(), type), filename));
    4644}
    4745
  • trunk/Source/WebCore/editing/cocoa/WebContentReaderCocoa.mm

    r222239 r222839  
    123123#endif
    124124
     125class DeferredLoadingScope {
     126public:
     127    DeferredLoadingScope(Frame& frame)
     128        : m_frame(frame)
     129        , m_cachedResourceLoader(frame.document()->cachedResourceLoader())
     130    {
     131        if (!frame.page()->defersLoading()) {
     132            frame.page()->setDefersLoading(true);
     133            m_didEnabledDeferredLoading = true;
     134        }
     135
     136        if (m_cachedResourceLoader->imagesEnabled()) {
     137            m_cachedResourceLoader->setImagesEnabled(false);
     138            m_didDisableImage = true;
     139        }
     140    }
     141
     142    ~DeferredLoadingScope()
     143    {
     144        if (m_didEnabledDeferredLoading)
     145            m_cachedResourceLoader->setImagesEnabled(true);
     146        if (m_didDisableImage)
     147            m_frame->page()->setDefersLoading(false);
     148    }
     149
     150private:
     151    Ref<Frame> m_frame;
     152    Ref<CachedResourceLoader> m_cachedResourceLoader;
     153    bool m_didEnabledDeferredLoading { false };
     154    bool m_didDisableImage { false };
     155};
     156
    125157RefPtr<DocumentFragment> createFragmentAndAddResources(Frame& frame, NSAttributedString *string)
    126158{
     
    132164        return nullptr;
    133165
    134     bool wasDeferringCallbacks = frame.page()->defersLoading();
    135     if (!wasDeferringCallbacks)
    136         frame.page()->setDefersLoading(true);
    137 
    138     auto& cachedResourceLoader = document.cachedResourceLoader();
    139     bool wasImagesEnabled = cachedResourceLoader.imagesEnabled();
    140     if (wasImagesEnabled)
    141         cachedResourceLoader.setImagesEnabled(false);
    142 
     166    DeferredLoadingScope scope(frame);
    143167    auto fragmentAndResources = createFragment(frame, string);
    144     if (auto* loader = frame.loader().documentLoader()) {
    145         for (auto& resource : fragmentAndResources.resources)
    146             loader->addArchiveResource(WTFMove(resource));
     168    if (!fragmentAndResources.fragment)
     169        return nullptr;
     170
     171    HashMap<AtomicString, AtomicString> blobURLMap;
     172    for (const Ref<ArchiveResource>& subresource : fragmentAndResources.resources) {
     173        auto blob = Blob::create(subresource->data(), subresource->mimeType());
     174        String blobURL = DOMURL::createObjectURL(document, blob);
     175        blobURLMap.set(subresource->url().string(), blobURL);
    147176    }
    148 
    149     if (wasImagesEnabled)
    150         cachedResourceLoader.setImagesEnabled(true);
    151     if (!wasDeferringCallbacks)
    152         frame.page()->setDefersLoading(false);
     177    replaceSubresourceURLs(*fragmentAndResources.fragment, WTFMove(blobURLMap));
    153178
    154179    return WTFMove(fragmentAndResources.fragment);
     
    226251bool WebContentReader::readImage(Ref<SharedBuffer>&& buffer, const String& type)
    227252{
    228     Vector<uint8_t> data;
    229     data.append(buffer->data(), buffer->size());
    230     auto blob = Blob::create(WTFMove(data), type);
     253    auto blob = Blob::create(buffer.get(), type);
    231254    ASSERT(frame.document());
    232255    auto& document = *frame.document();
  • trunk/Source/WebCore/editing/markup.cpp

    r222220 r222839  
    117117        change.apply();
    118118}
     119
     120void replaceSubresourceURLs(Ref<DocumentFragment>&& fragment, HashMap<AtomicString, AtomicString>&& replacementMap)
     121{
     122    Vector<AttributeChange> changes;
     123    for (auto& element : descendantsOfType<Element>(fragment)) {
     124        if (!element.hasAttributes())
     125            continue;
     126        for (const Attribute& attribute : element.attributesIterator()) {
     127            // FIXME: This won't work for srcset.
     128            if (element.attributeContainsURL(attribute) && !attribute.value().isEmpty()) {
     129                auto replacement = replacementMap.get(attribute.value());
     130                if (!replacement.isNull())
     131                    changes.append({ &element, attribute.name(), replacement });
     132            }
     133        }
     134    }
     135    for (auto& change : changes)
     136        change.apply();
     137}
    119138   
    120139class StyledMarkupAccumulator final : public MarkupAccumulator {
  • trunk/Source/WebCore/editing/markup.h

    r222119 r222839  
    3030#include "HTMLInterchange.h"
    3131#include <wtf/Forward.h>
     32#include <wtf/HashMap.h>
    3233
    3334namespace WebCore {
     
    4445class QualifiedName;
    4546class Range;
     47
     48void replaceSubresourceURLs(Ref<DocumentFragment>&&, HashMap<AtomicString, AtomicString>&&);
    4649
    4750enum EChildrenOnly { IncludeNode, ChildrenOnly };
  • trunk/Source/WebCore/fileapi/Blob.cpp

    r221936 r222839  
    3737#include "File.h"
    3838#include "ScriptExecutionContext.h"
     39#include "SharedBuffer.h"
    3940#include "ThreadableBlobRegistry.h"
    4041#include <wtf/NeverDestroyed.h>
     
    9798}
    9899
     100Blob::Blob(const SharedBuffer& buffer, const String& contentType)
     101    : m_type(contentType)
     102    , m_size(buffer.size())
     103{
     104    Vector<uint8_t> data;
     105    data.append(buffer.data(), buffer.size());
     106
     107    Vector<BlobPart> blobParts;
     108    blobParts.append(BlobPart(WTFMove(data)));
     109    m_internalURL = BlobURL::createInternalURL();
     110    ThreadableBlobRegistry::registerBlobURL(m_internalURL, WTFMove(blobParts), contentType);
     111}
     112
    99113Blob::Blob(Vector<uint8_t>&& data, const String& contentType)
    100114    : m_type(contentType)
  • trunk/Source/WebCore/fileapi/Blob.h

    r221936 r222839  
    4646class Blob;
    4747class ScriptExecutionContext;
     48class SharedBuffer;
    4849
    4950using BlobPartVariant = Variant<RefPtr<JSC::ArrayBufferView>, RefPtr<JSC::ArrayBuffer>, RefPtr<Blob>, String>;
     
    5960    {
    6061        return adoptRef(*new Blob(WTFMove(blobPartVariants), propertyBag));
     62    }
     63
     64    static Ref<Blob> create(const SharedBuffer& buffer, const String& contentType)
     65    {
     66        return adoptRef(*new Blob(buffer, contentType));
    6167    }
    6268
     
    100106    Blob();
    101107    Blob(Vector<BlobPartVariant>&&, const BlobPropertyBag&);
     108    Blob(const SharedBuffer&, const String& contentType);
    102109    Blob(Vector<uint8_t>&&, const String& contentType);
    103110
  • trunk/Source/WebKit/ChangeLog

    r222837 r222839  
     12017-10-04  Ryosuke Niwa  <rniwa@webkit.org>
     2
     3        Use blob URL when pasting RTFD instead of overriding DocumentLoader
     4        https://bugs.webkit.org/show_bug.cgi?id=177801
     5        <rdar://problem/34542270>
     6
     7        Reviewed by Wenson Hsieh.
     8
     9        Fixed the assertion failure when RTFD content is empty.
     10
     11        * UIProcess/Cocoa/WebPasteboardProxyCocoa.mm:
     12        (WebKit::WebPasteboardProxy::getPasteboardBufferForType):
     13
    1142017-10-04  Michael Catanzaro  <mcatanzaro@igalia.com>
    215
  • trunk/Source/WebKit/UIProcess/Cocoa/WebPasteboardProxyCocoa.mm

    r222656 r222839  
    7676        return;
    7777    size = buffer->size();
     78    if (!size)
     79        return;
    7880    RefPtr<SharedMemory> sharedMemoryBuffer = SharedMemory::allocate(size);
    7981    if (!sharedMemoryBuffer)
  • trunk/Tools/ChangeLog

    r222834 r222839  
     12017-10-04  Ryosuke Niwa  <rniwa@webkit.org>
     2
     3        Use blob URL when pasting RTFD instead of overriding DocumentLoader
     4        https://bugs.webkit.org/show_bug.cgi?id=177801
     5        <rdar://problem/34542270>
     6
     7        Reviewed by Wenson Hsieh.
     8
     9        Added a regression test for an assertion failure when pasting an empty RTFD as well as a test for pasting
     10        RTFD with an image, which should result in an image element with a blob URL.
     11
     12        * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
     13        * TestWebKitAPI/Tests/WebKitCocoa/PasteImage.mm:
     14        * TestWebKitAPI/Tests/WebKitCocoa/PasteRTFD.mm:
     15        * TestWebKitAPI/Tests/WebKitCocoa/paste-rtfd.html:
     16
    1172017-10-03  Gustavo Noronha Silva  <gustavo.noronha@collabora.co.uk>
    218
  • trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj

    r222820 r222839  
    546546                9B270FEE1DDC2C0B002D53F3 /* closed-shadow-tree-test.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 9B270FED1DDC25FD002D53F3 /* closed-shadow-tree-test.html */; };
    547547                9B4F8FA7159D52DD002D9F94 /* HTMLCollectionNamedItem.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 9B4F8FA6159D52CA002D9F94 /* HTMLCollectionNamedItem.html */; };
     548                9B7D740F1F8378770006C432 /* paste-rtfd.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 9B7D740E1F8377E60006C432 /* paste-rtfd.html */; };
    548549                9BD4239A1E04BD9800200395 /* AttributedSubstringForProposedRangeWithImage.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9BD423991E04BD9800200395 /* AttributedSubstringForProposedRangeWithImage.mm */; };
    549550                9BD4239C1E04C01C00200395 /* chinese-character-with-image.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 9BD4239B1E04BFD000200395 /* chinese-character-with-image.html */; };
     
    554555                9BD6D3A71F7B21DC00BD4962 /* paste-image.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 9BD6D3A61F7B21CC00BD4962 /* paste-image.html */; };
    555556                9BDCCD871F7D0B0700009A18 /* PasteImage.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9BDCCD851F7D0B0700009A18 /* PasteImage.mm */; };
     557                9BDD95581F83683600D20C60 /* PasteRTFD.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9BDD95561F83683600D20C60 /* PasteRTFD.mm */; };
    556558                9C64DC321D76198A004B598E /* YouTubePluginReplacement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9C64DC311D76198A004B598E /* YouTubePluginReplacement.cpp */; };
    557559                A10F047E1E3AD29C00C95E19 /* NSFileManagerExtras.mm in Sources */ = {isa = PBXBuildFile; fileRef = A10F047C1E3AD29C00C95E19 /* NSFileManagerExtras.mm */; };
     
    979981                                A1409AD91E7254D4004949D9 /* password-protected.pages in Copy Resources */,
    980982                                9BD6D3A71F7B21DC00BD4962 /* paste-image.html in Copy Resources */,
     983                                9B7D740F1F8378770006C432 /* paste-rtfd.html in Copy Resources */,
    981984                                3FCC4FE81EC4E8CA0076E37C /* PictureInPictureDelegate.html in Copy Resources */,
    982985                                F415086D1DA040C50044BE9B /* play-audio-on-click.html in Copy Resources */,
     
    15081511                9B4F8FA6159D52CA002D9F94 /* HTMLCollectionNamedItem.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = HTMLCollectionNamedItem.html; sourceTree = "<group>"; };
    15091512                9B79164F1BD89D0D00D50B8F /* FirstResponderScrollingPosition.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FirstResponderScrollingPosition.mm; sourceTree = "<group>"; };
     1513                9B7D740E1F8377E60006C432 /* paste-rtfd.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "paste-rtfd.html"; sourceTree = "<group>"; };
    15101514                9BD423991E04BD9800200395 /* AttributedSubstringForProposedRangeWithImage.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = AttributedSubstringForProposedRangeWithImage.mm; sourceTree = "<group>"; };
    15111515                9BD4239B1E04BFD000200395 /* chinese-character-with-image.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "chinese-character-with-image.html"; sourceTree = "<group>"; };
     
    15161520                9BD6D3A61F7B21CC00BD4962 /* paste-image.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "paste-image.html"; sourceTree = "<group>"; };
    15171521                9BDCCD851F7D0B0700009A18 /* PasteImage.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = PasteImage.mm; sourceTree = "<group>"; };
     1522                9BDD95561F83683600D20C60 /* PasteRTFD.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = PasteRTFD.mm; sourceTree = "<group>"; };
    15181523                9C64DC311D76198A004B598E /* YouTubePluginReplacement.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = YouTubePluginReplacement.cpp; sourceTree = "<group>"; };
    15191524                A10F047C1E3AD29C00C95E19 /* NSFileManagerExtras.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = NSFileManagerExtras.mm; sourceTree = "<group>"; };
     
    20152020                                CEBCA12E1E3A660100C73293 /* OverrideContentSecurityPolicy.mm */,
    20162021                                9BDCCD851F7D0B0700009A18 /* PasteImage.mm */,
     2022                                9BDD95561F83683600D20C60 /* PasteRTFD.mm */,
    20172023                                3FCC4FE41EC4E8520076E37C /* PictureInPictureDelegate.mm */,
    20182024                                83BAEE8C1EF4625500DDE894 /* PluginLoadClientPolicies.mm */,
     
    23092315                                A1409AD81E7254AC004949D9 /* password-protected.pages */,
    23102316                                9BD6D3A61F7B21CC00BD4962 /* paste-image.html */,
     2317                                9B7D740E1F8377E60006C432 /* paste-rtfd.html */,
    23112318                                3FCC4FE61EC4E87E0076E37C /* PictureInPictureDelegate.html */,
    23122319                                F415086C1DA040C10044BE9B /* play-audio-on-click.html */,
     
    33753382                                7CCE7F0A1A411AE600447C4C /* PasteboardNotifications.mm in Sources */,
    33763383                                9BDCCD871F7D0B0700009A18 /* PasteImage.mm in Sources */,
     3384                                9BDD95581F83683600D20C60 /* PasteRTFD.mm in Sources */,
    33773385                                7C83E0531D0A643A00FEBCF3 /* PendingAPIRequestURL.cpp in Sources */,
    33783386                                3FCC4FE51EC4E8520076E37C /* PictureInPictureDelegate.mm in Sources */,
  • trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/PasteImage.mm

    r222656 r222839  
    2828#if WK_API_ENABLED && PLATFORM(COCOA)
    2929
    30 #import "AppKitSPI.h"
    3130#import "PlatformUtilities.h"
    3231#import "TestWKWebView.h"
    33 #import <wtf/BlockPtr.h>
    3432#import <wtf/RetainPtr.h>
    3533#import <wtf/text/WTFString.h>
Note: See TracChangeset for help on using the changeset viewer.