Changeset 215263 in webkit


Ignore:
Timestamp:
Apr 12, 2017 3:09:14 AM (7 years ago)
Author:
Antti Koivisto
Message:

Cache small media resources in disk cache
https://bugs.webkit.org/show_bug.cgi?id=170676
<rdar://problem/31532649>

Reviewed by Andreas Kling.

Source/WebCore:

Test: http/tests/cache/disk-cache/disk-cache-media-small.html

Testing support. Functional changes are in WebKit2.

  • html/HTMLMediaElement.cpp:

(WebCore::HTMLMediaElement::mediaPlayerCreateResourceLoader):
(WebCore::HTMLMediaElement::lastMediaResourceLoaderForTesting):

  • html/HTMLMediaElement.h:
  • loader/MediaResourceLoader.cpp:

(WebCore::MediaResourceLoader::MediaResourceLoader):
(WebCore::MediaResourceLoader::addResponseForTesting):
(WebCore::MediaResource::responseReceived):

  • loader/MediaResourceLoader.h:
  • platform/network/cocoa/WebCoreNSURLSession.mm:

(-[WebCoreNSURLSessionDataTask resource:receivedResponse:]):

We can now receive cached responses.

  • testing/Internals.cpp:

(WebCore::responseSourceToString):
(WebCore::Internals::xhrResponseSource):
(WebCore::Internals::mediaResponseSources):
(WebCore::Internals::mediaResponseContentRanges):

  • testing/Internals.h:
  • testing/Internals.idl:

Source/WebKit2:

  • NetworkProcess/cache/NetworkCache.cpp:

(WebKit::NetworkCache::makeRetrieveDecision):

Allow retrieving media resources.

(WebKit::NetworkCache::expectedTotalResourceSizeFromContentRange):
(WebKit::NetworkCache::expectedTotalResourceSize):
(WebKit::NetworkCache::makeStoreDecision):

Store media resource if we can figure out its total size and it is less than 5MB
(and it is cacheable by the usual rules).

LayoutTests:

  • http/tests/cache/disk-cache/disk-cache-media-small-expected.txt: Added.
  • http/tests/cache/disk-cache/disk-cache-media-small.html: Added.
Location:
trunk
Files:
2 added
15 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r215261 r215263  
     12017-04-10  Antti Koivisto  <antti@apple.com>
     2
     3        Cache small media resources in disk cache
     4        https://bugs.webkit.org/show_bug.cgi?id=170676
     5        <rdar://problem/31532649>
     6
     7        Reviewed by Andreas Kling.
     8
     9        * http/tests/cache/disk-cache/disk-cache-media-small-expected.txt: Added.
     10        * http/tests/cache/disk-cache/disk-cache-media-small.html: Added.
     11
    1122017-04-12  Per Arne Vollan  <pvollan@apple.com>
    213
  • trunk/LayoutTests/platform/ios/TestExpectations

    r215145 r215263  
    138138http/tests/media
    139139imported/w3c/web-platform-tests/html/semantics/embedded-content/media-elements
     140http/tests/cache/disk-cache/disk-cache-media-small.html
    140141
    141142# No touch events
  • trunk/LayoutTests/platform/mac-wk2/TestExpectations

    r215222 r215263  
    647647webkit.org/b/170410 fast/images/animated-gif-webkit-transform.html [ Pass Failure ]
    648648
     649# Media loading via network cache requires Sierra or newer.
     650[ ElCapitan ] http/tests/cache/disk-cache/disk-cache-media-small.html [ Failure ]
     651
    649652compositing/tiling/non-visible-window-tile-coverage.html [ Pass ]
  • trunk/Source/WebCore/ChangeLog

    r215262 r215263  
     12017-04-10  Antti Koivisto  <antti@apple.com>
     2
     3        Cache small media resources in disk cache
     4        https://bugs.webkit.org/show_bug.cgi?id=170676
     5        <rdar://problem/31532649>
     6
     7        Reviewed by Andreas Kling.
     8
     9        Test: http/tests/cache/disk-cache/disk-cache-media-small.html
     10
     11        Testing support. Functional changes are in WebKit2.
     12
     13        * html/HTMLMediaElement.cpp:
     14        (WebCore::HTMLMediaElement::mediaPlayerCreateResourceLoader):
     15        (WebCore::HTMLMediaElement::lastMediaResourceLoaderForTesting):
     16        * html/HTMLMediaElement.h:
     17        * loader/MediaResourceLoader.cpp:
     18        (WebCore::MediaResourceLoader::MediaResourceLoader):
     19        (WebCore::MediaResourceLoader::addResponseForTesting):
     20        (WebCore::MediaResource::responseReceived):
     21        * loader/MediaResourceLoader.h:
     22        * platform/network/cocoa/WebCoreNSURLSession.mm:
     23        (-[WebCoreNSURLSessionDataTask resource:receivedResponse:]):
     24
     25            We can now receive cached responses.
     26
     27        * testing/Internals.cpp:
     28        (WebCore::responseSourceToString):
     29        (WebCore::Internals::xhrResponseSource):
     30        (WebCore::Internals::mediaResponseSources):
     31        (WebCore::Internals::mediaResponseContentRanges):
     32        * testing/Internals.h:
     33        * testing/Internals.idl:
     34
    1352017-04-12  Alex Christensen  <achristensen@webkit.org>
    236
  • trunk/Source/WebCore/html/HTMLMediaElement.cpp

    r215249 r215263  
    65146514RefPtr<PlatformMediaResourceLoader> HTMLMediaElement::mediaPlayerCreateResourceLoader()
    65156515{
    6516     return adoptRef(*new MediaResourceLoader(document(), *this, crossOrigin()));
     6516    auto mediaResourceLoader = adoptRef(*new MediaResourceLoader(document(), *this, crossOrigin()));
     6517
     6518    m_lastMediaResourceLoaderForTesting = mediaResourceLoader->createWeakPtr();
     6519
     6520    return WTFMove(mediaResourceLoader);
     6521}
     6522
     6523const MediaResourceLoader* HTMLMediaElement::lastMediaResourceLoaderForTesting() const
     6524{
     6525    return m_lastMediaResourceLoaderForTesting.get();
    65176526}
    65186527
  • trunk/Source/WebCore/html/HTMLMediaElement.h

    r215167 r215263  
    3939#include "UserInterfaceLayoutDirection.h"
    4040#include "VisibilityChangeClient.h"
     41#include <wtf/WeakPtr.h>
    4142
    4243#if ENABLE(VIDEO_TRACK)
     
    7475class MediaKeys;
    7576class MediaPlayer;
     77class MediaResourceLoader;
    7678class MediaSession;
    7779class MediaSource;
     
    501503
    502504    void isVisibleInViewportChanged();
     505
     506    WEBCORE_EXPORT const MediaResourceLoader* lastMediaResourceLoaderForTesting() const;
    503507
    504508protected:
     
    10341038    std::unique_ptr<DisplaySleepDisabler> m_sleepDisabler;
    10351039
     1040    WeakPtr<const MediaResourceLoader> m_lastMediaResourceLoaderForTesting;
     1041
    10361042    friend class TrackDisplayUpdateScope;
    10371043
  • trunk/Source/WebCore/loader/MediaResourceLoader.cpp

    r212994 r215263  
    4646    , m_mediaElement(&mediaElement)
    4747    , m_crossOriginMode(crossOriginMode)
     48    , m_weakFactory(this)
    4849{
    4950}
     
    9596    ASSERT(m_resources.contains(&mediaResource));
    9697    m_resources.remove(&mediaResource);
     98}
     99
     100void MediaResourceLoader::addResponseForTesting(const ResourceResponse& response)
     101{
     102    const auto maximumResponsesForTesting = 5;
     103    if (m_responsesForTesting.size() > maximumResponsesForTesting)
     104        return;
     105    m_responsesForTesting.append(response);
    97106}
    98107
     
    152161    if (m_client)
    153162        m_client->responseReceived(*this, response);
     163
     164    m_loader->addResponseForTesting(response);
    154165}
    155166
  • trunk/Source/WebCore/loader/MediaResourceLoader.h

    r212994 r215263  
    3232#include "ContextDestructionObserver.h"
    3333#include "PlatformMediaResourceLoader.h"
     34#include "ResourceResponse.h"
    3435#include <wtf/HashSet.h>
    3536#include <wtf/Ref.h>
     37#include <wtf/WeakPtr.h>
    3638#include <wtf/text/WTFString.h>
    3739
     
    5456    const String& crossOriginMode() const { return m_crossOriginMode; }
    5557
     58    Vector<ResourceResponse> responsesForTesting() const { return m_responsesForTesting; }
     59    void addResponseForTesting(const ResourceResponse&);
     60
     61    WeakPtr<const MediaResourceLoader> createWeakPtr() const { return m_weakFactory.createWeakPtr(); }
     62
    5663private:
    5764    void contextDestroyed() override;
     
    6168    String m_crossOriginMode;
    6269    HashSet<MediaResource*> m_resources;
     70    WeakPtrFactory<const MediaResourceLoader> m_weakFactory;
     71    Vector<ResourceResponse> m_responsesForTesting;
    6372};
    6473
  • trunk/Source/WebCore/platform/network/cocoa/WebCoreNSURLSession.mm

    r204210 r215263  
    552552- (void)resource:(PlatformMediaResource&)resource receivedResponse:(const ResourceResponse&)response
    553553{
    554     ASSERT(response.source() == ResourceResponse::Source::Network);
     554    ASSERT(response.source() == ResourceResponse::Source::Network || response.source() == ResourceResponse::Source::DiskCache || response.source() == ResourceResponse::Source::DiskCacheAfterValidation);
    555555    ASSERT_UNUSED(resource, &resource == _resource);
    556556    ASSERT(isMainThread());
  • trunk/Source/WebCore/testing/Internals.cpp

    r215242 r215263  
    9393#include "MediaPlayer.h"
    9494#include "MediaProducer.h"
     95#include "MediaResourceLoader.h"
    9596#include "MediaStreamTrack.h"
    9697#include "MemoryCache.h"
     
    603604}
    604605
    605 String Internals::xhrResponseSource(XMLHttpRequest& request)
    606 {
    607     if (request.resourceResponse().isNull())
     606static String responseSourceToString(const ResourceResponse& response)
     607{
     608    if (response.isNull())
    608609        return "Null response";
    609     switch (request.resourceResponse().source()) {
     610    switch (response.source()) {
    610611    case ResourceResponse::Source::Unknown:
    611612        return "Unknown";
     
    623624    ASSERT_NOT_REACHED();
    624625    return "Error";
     626}
     627
     628String Internals::xhrResponseSource(XMLHttpRequest& request)
     629{
     630    return responseSourceToString(request.resourceResponse());
     631}
     632
     633Vector<String> Internals::mediaResponseSources(HTMLMediaElement& media)
     634{
     635    auto* resourceLoader = media.lastMediaResourceLoaderForTesting();
     636    if (!resourceLoader)
     637        return { };
     638    Vector<String> result;
     639    auto responses = resourceLoader->responsesForTesting();
     640    for (auto& response : responses)
     641        result.append(responseSourceToString(response));
     642    return result;
     643}
     644
     645Vector<String> Internals::mediaResponseContentRanges(HTMLMediaElement& media)
     646{
     647    auto* resourceLoader = media.lastMediaResourceLoaderForTesting();
     648    if (!resourceLoader)
     649        return { };
     650    Vector<String> result;
     651    auto responses = resourceLoader->responsesForTesting();
     652    for (auto& response : responses)
     653        result.append(response.httpHeaderField(HTTPHeaderName::ContentRange));
     654    return result;
    625655}
    626656
  • trunk/Source/WebCore/testing/Internals.h

    r215181 r215263  
    103103    bool isLoadingFromMemoryCache(const String& url);
    104104    String xhrResponseSource(XMLHttpRequest&);
     105    Vector<String> mediaResponseSources(HTMLMediaElement&);
     106    Vector<String> mediaResponseContentRanges(HTMLMediaElement&);
    105107    bool isSharingStyleSheetContents(HTMLLinkElement&, HTMLLinkElement&);
    106108    bool isStyleSheetLoadingSubresources(HTMLLinkElement&);
  • trunk/Source/WebCore/testing/Internals.idl

    r215181 r215263  
    9898    boolean isLoadingFromMemoryCache(DOMString url);
    9999    DOMString xhrResponseSource(XMLHttpRequest xhr);
     100    sequence<DOMString> mediaResponseSources(HTMLMediaElement media);
     101    sequence<DOMString> mediaResponseContentRanges(HTMLMediaElement media);
    100102    boolean isSharingStyleSheetContents(HTMLLinkElement a, HTMLLinkElement b);
    101103    boolean isStyleSheetLoadingSubresources(HTMLLinkElement link);
  • trunk/Source/WebKit2/ChangeLog

    r215262 r215263  
     12017-04-10  Antti Koivisto  <antti@apple.com>
     2
     3        Cache small media resources in disk cache
     4        https://bugs.webkit.org/show_bug.cgi?id=170676
     5        <rdar://problem/31532649>
     6
     7        Reviewed by Andreas Kling.
     8
     9        * NetworkProcess/cache/NetworkCache.cpp:
     10        (WebKit::NetworkCache::makeRetrieveDecision):
     11
     12            Allow retrieving media resources.
     13
     14        (WebKit::NetworkCache::expectedTotalResourceSizeFromContentRange):
     15        (WebKit::NetworkCache::expectedTotalResourceSize):
     16        (WebKit::NetworkCache::makeStoreDecision):
     17
     18            Store media resource if we can figure out its total size and it is less than 5MB
     19            (and it is cacheable by the usual rules).
     20
    1212017-04-12  Alex Christensen  <achristensen@webkit.org>
    222
  • trunk/Source/WebKit2/NetworkProcess/cache/NetworkCache.cpp

    r215044 r215263  
    213213    if (request.httpMethod() != "GET")
    214214        return RetrieveDecision::NoDueToHTTPMethod;
    215     if (request.requester() == WebCore::ResourceRequest::Requester::Media)
    216         return RetrieveDecision::NoDueToStreamingMedia;
    217215    if (request.cachePolicy() == WebCore::ReloadIgnoringCacheData && !request.isConditional())
    218216        return RetrieveDecision::NoDueToReloadIgnoringCache;
     
    230228}
    231229
    232 static StoreDecision makeStoreDecision(const WebCore::ResourceRequest& originalRequest, const WebCore::ResourceResponse& response)
     230static std::optional<size_t> expectedTotalResourceSizeFromContentRange(const WebCore::ResourceResponse& response)
     231{
     232    ASSERT(response.httpStatusCode() == 206);
     233
     234    auto contentRange = response.httpHeaderField(WebCore::HTTPHeaderName::ContentRange);
     235    if (contentRange.isNull())
     236        return { };
     237
     238    if (!contentRange.startsWith("bytes "))
     239        return { };
     240
     241    auto slashPosition = contentRange.find('/');
     242    if (slashPosition == notFound)
     243        return { };
     244
     245    auto sizeStringLength = contentRange.length() - slashPosition - 1;
     246    if (!sizeStringLength)
     247        return { };
     248
     249    bool isValid;
     250    auto size = StringView(contentRange).right(sizeStringLength).toIntStrict(isValid);
     251    if (!isValid)
     252        return { };
     253
     254    return size;
     255}
     256
     257static StoreDecision makeStoreDecision(const WebCore::ResourceRequest& originalRequest, const WebCore::ResourceResponse& response, size_t bodySize)
    233258{
    234259    if (!originalRequest.url().protocolIsInHTTPFamily() || !response.isHTTP())
     
    264289    }
    265290
    266     // Media loaded via XHR is likely being used for MSE streaming (YouTube and Netflix for example).
    267291    // Streaming media fills the cache quickly and is unlikely to be reused.
    268292    // FIXME: We should introduce a separate media cache partition that doesn't affect other resources.
    269293    // FIXME: We should also make sure make the MSE paths are copy-free so we can use mapped buffers from disk effectively.
    270294    auto requester = originalRequest.requester();
    271     bool isDefinitelyStreamingMedia = requester == WebCore::ResourceRequest::Requester::Media;
     295    bool isDefinitelyMedia = requester == WebCore::ResourceRequest::Requester::Media;
     296    if (isDefinitelyMedia) {
     297        // Allow caching of smaller media files if we know the total size.
     298        const size_t maximumCacheableMediaSize = 5 * 1024 * 1024;
     299        auto totalSize = response.httpStatusCode() == 206 ? expectedTotalResourceSizeFromContentRange(response) : bodySize;
     300        if (!totalSize || *totalSize > maximumCacheableMediaSize)
     301            return StoreDecision::NoDueToStreamingMedia;
     302    }
     303
    272304    bool isLikelyStreamingMedia = requester == WebCore::ResourceRequest::Requester::XHR && isMediaMIMEType(response.mimeType());
    273     if (isLikelyStreamingMedia || isDefinitelyStreamingMedia)
     305    if (isLikelyStreamingMedia) {
     306        // Media loaded via XHR is likely being used for MSE streaming (YouTube and Netflix for example).
     307        // We have no way of knowing the total media size so disallow caching.
    274308        return StoreDecision::NoDueToStreamingMedia;
     309    }
    275310
    276311    return StoreDecision::Yes;
     
    375410    LOG(NetworkCache, "(NetworkProcess) storing %s, partition %s", request.url().string().latin1().data(), makeCacheKey(request).partition().latin1().data());
    376411
    377     StoreDecision storeDecision = makeStoreDecision(request, response);
     412    StoreDecision storeDecision = makeStoreDecision(request, response, responseData ? responseData->size() : 0);
    378413    if (storeDecision != StoreDecision::Yes) {
    379414        LOG(NetworkCache, "(NetworkProcess) didn't store, storeDecision=%d", static_cast<int>(storeDecision));
     
    419454    LOG(NetworkCache, "(NetworkProcess) storing redirect %s -> %s", request.url().string().latin1().data(), redirectRequest.url().string().latin1().data());
    420455
    421     StoreDecision storeDecision = makeStoreDecision(request, response);
     456    StoreDecision storeDecision = makeStoreDecision(request, response, 0);
    422457    if (storeDecision != StoreDecision::Yes) {
    423458        LOG(NetworkCache, "(NetworkProcess) didn't store redirect, storeDecision=%d", static_cast<int>(storeDecision));
  • trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheSpeculativeLoadManager.cpp

    r215152 r215263  
    365365    if (request.httpMethod() != "GET")
    366366        return;
     367    if (!request.httpHeaderField(HTTPHeaderName::Range).isEmpty())
     368        return;
    367369
    368370    auto isMainResource = request.requester() == ResourceRequest::Requester::Main;
Note: See TracChangeset for help on using the changeset viewer.