Home | History | Annotate | Download | only in loader
      1 /*
      2  * Copyright (C) 2011 Google Inc.  All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  * 1. Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  * 2. Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
     14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
     17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 
     26 #include "config.h"
     27 
     28 #include "core/loader/TextTrackLoader.h"
     29 
     30 #include "FetchInitiatorTypeNames.h"
     31 #include "core/dom/Document.h"
     32 #include "core/html/track/WebVTTParser.h"
     33 #include "core/loader/CrossOriginAccessControl.h"
     34 #include "core/loader/cache/FetchRequest.h"
     35 #include "core/loader/cache/ResourceFetcher.h"
     36 #include "core/loader/cache/TextTrackResource.h"
     37 #include "core/platform/Logging.h"
     38 #include "core/platform/SharedBuffer.h"
     39 #include "weborigin/SecurityOrigin.h"
     40 
     41 namespace WebCore {
     42 
     43 TextTrackLoader::TextTrackLoader(TextTrackLoaderClient* client, ScriptExecutionContext* context)
     44     : m_client(client)
     45     , m_scriptExecutionContext(context)
     46     , m_cueLoadTimer(this, &TextTrackLoader::cueLoadTimerFired)
     47     , m_state(Idle)
     48     , m_parseOffset(0)
     49     , m_newCuesAvailable(false)
     50 {
     51 }
     52 
     53 TextTrackLoader::~TextTrackLoader()
     54 {
     55     if (m_cachedCueData)
     56         m_cachedCueData->removeClient(this);
     57 }
     58 
     59 void TextTrackLoader::cueLoadTimerFired(Timer<TextTrackLoader>* timer)
     60 {
     61     ASSERT_UNUSED(timer, timer == &m_cueLoadTimer);
     62 
     63     if (m_newCuesAvailable) {
     64         m_newCuesAvailable = false;
     65         m_client->newCuesAvailable(this);
     66     }
     67 
     68     if (m_state >= Finished)
     69         m_client->cueLoadingCompleted(this, m_state == Failed);
     70 }
     71 
     72 void TextTrackLoader::cancelLoad()
     73 {
     74     if (m_cachedCueData) {
     75         m_cachedCueData->removeClient(this);
     76         m_cachedCueData = 0;
     77     }
     78 }
     79 
     80 void TextTrackLoader::processNewCueData(Resource* resource)
     81 {
     82     ASSERT(m_cachedCueData == resource);
     83 
     84     if (m_state == Failed || !resource->resourceBuffer())
     85         return;
     86 
     87     SharedBuffer* buffer = resource->resourceBuffer();
     88     if (m_parseOffset == buffer->size())
     89         return;
     90 
     91     if (!m_cueParser)
     92         m_cueParser = WebVTTParser::create(this, m_scriptExecutionContext);
     93 
     94     const char* data;
     95     unsigned length;
     96 
     97     while ((length = buffer->getSomeData(data, m_parseOffset))) {
     98         m_cueParser->parseBytes(data, length);
     99         m_parseOffset += length;
    100     }
    101 }
    102 
    103 // FIXME: This is a very unusual pattern, no other ResourceClient does this. Refactor to use notifyFinished() instead.
    104 void TextTrackLoader::deprecatedDidReceiveResource(Resource* resource)
    105 {
    106     ASSERT(m_cachedCueData == resource);
    107 
    108     if (!resource->resourceBuffer())
    109         return;
    110 
    111     processNewCueData(resource);
    112 }
    113 
    114 void TextTrackLoader::corsPolicyPreventedLoad()
    115 {
    116     DEFINE_STATIC_LOCAL(String, consoleMessage, ("Cross-origin text track load denied by Cross-Origin Resource Sharing policy."));
    117     Document* document = toDocument(m_scriptExecutionContext);
    118     document->addConsoleMessage(SecurityMessageSource, ErrorMessageLevel, consoleMessage);
    119     m_state = Failed;
    120 }
    121 
    122 void TextTrackLoader::notifyFinished(Resource* resource)
    123 {
    124     ASSERT(m_cachedCueData == resource);
    125 
    126     Document* document = toDocument(m_scriptExecutionContext);
    127     if (!m_crossOriginMode.isNull()
    128         && !document->securityOrigin()->canRequest(resource->response().url())
    129         && !resource->passesAccessControlCheck(document->securityOrigin())) {
    130 
    131         corsPolicyPreventedLoad();
    132     }
    133 
    134     if (m_state != Failed) {
    135         processNewCueData(resource);
    136         if (m_state != Failed)
    137             m_state = resource->errorOccurred() ? Failed : Finished;
    138     }
    139 
    140     if (!m_cueLoadTimer.isActive())
    141         m_cueLoadTimer.startOneShot(0);
    142 
    143     cancelLoad();
    144 }
    145 
    146 bool TextTrackLoader::load(const KURL& url, const String& crossOriginMode)
    147 {
    148     cancelLoad();
    149 
    150     if (!m_client->shouldLoadCues(this))
    151         return false;
    152 
    153     ASSERT(m_scriptExecutionContext->isDocument());
    154     Document* document = toDocument(m_scriptExecutionContext);
    155     FetchRequest cueRequest(ResourceRequest(document->completeURL(url)), FetchInitiatorTypeNames::texttrack);
    156 
    157     if (!crossOriginMode.isNull()) {
    158         m_crossOriginMode = crossOriginMode;
    159         StoredCredentials allowCredentials = equalIgnoringCase(crossOriginMode, "use-credentials") ? AllowStoredCredentials : DoNotAllowStoredCredentials;
    160         updateRequestForAccessControl(cueRequest.mutableResourceRequest(), document->securityOrigin(), allowCredentials);
    161     } else {
    162         // Cross-origin resources that are not suitably CORS-enabled may not load.
    163         if (!document->securityOrigin()->canRequest(url)) {
    164             corsPolicyPreventedLoad();
    165             return false;
    166         }
    167     }
    168 
    169     ResourceFetcher* fetcher = document->fetcher();
    170     m_cachedCueData = fetcher->requestTextTrack(cueRequest);
    171     if (m_cachedCueData)
    172         m_cachedCueData->addClient(this);
    173 
    174     m_client->cueLoadingStarted(this);
    175 
    176     return true;
    177 }
    178 
    179 void TextTrackLoader::newCuesParsed()
    180 {
    181     if (m_cueLoadTimer.isActive())
    182         return;
    183 
    184     m_newCuesAvailable = true;
    185     m_cueLoadTimer.startOneShot(0);
    186 }
    187 
    188 #if ENABLE(WEBVTT_REGIONS)
    189 void TextTrackLoader::newRegionsParsed()
    190 {
    191     m_client->newRegionsAvailable(this);
    192 }
    193 #endif
    194 
    195 void TextTrackLoader::fileFailedToParse()
    196 {
    197     LOG(Media, "TextTrackLoader::fileFailedToParse");
    198 
    199     m_state = Failed;
    200 
    201     if (!m_cueLoadTimer.isActive())
    202         m_cueLoadTimer.startOneShot(0);
    203 
    204     cancelLoad();
    205 }
    206 
    207 void TextTrackLoader::getNewCues(Vector<RefPtr<TextTrackCue> >& outputCues)
    208 {
    209     ASSERT(m_cueParser);
    210     if (m_cueParser)
    211         m_cueParser->getNewCues(outputCues);
    212 }
    213 
    214 #if ENABLE(WEBVTT_REGIONS)
    215 void TextTrackLoader::getNewRegions(Vector<RefPtr<TextTrackRegion> >& outputRegions)
    216 {
    217     ASSERT(m_cueParser);
    218     if (m_cueParser)
    219         m_cueParser->getNewRegions(outputRegions);
    220 }
    221 #endif
    222 }
    223 
    224