WebCore:
authorantti@apple.com <antti@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 17 Jan 2008 00:34:50 +0000 (00:34 +0000)
committerantti@apple.com <antti@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 17 Jan 2008 00:34:50 +0000 (00:34 +0000)
        Reviewed by Adele.

        OS X fix for <rdar://problem/5605682>
        Disallow streaming protocols for media elements
        and <rdar://problem/5668711>
        Limit the container and codec types that the <video> tag supports

        - Disable unsupported QuickTime tracks types.
        - Disallow streaming protocols (for now).
        - Set QTMovie QTMoviePreventExternalURLLinksAttribute and QTSecurityPolicyNoCrossSiteAttribute
          to limit QuickTime's access to external resources.

        Windows patch coming up.

        Tests: media/broken-video.html
               media/unsupported-rtsp.html
               media/unsupported-tracks.html

        * platform/graphics/mac/MediaPlayerPrivateQTKit.h:
        * platform/graphics/mac/MediaPlayerPrivateQTKit.mm:
        (WebCore::MediaPlayerPrivate::createQTMovie):
        (WebCore::MediaPlayerPrivate::updateStates):
        (WebCore::MediaPlayerPrivate::disableUnsupportedTracks):

LayoutTests:

        Reviewed by Adele.

        Tests for <rdar://problem/5605682>
        Disallow streaming protocols for media elements
        and <rdar://problem/5668711>
        Limit the container and codec types that the <video> tag supports

        - test that rtsp: protocol is disabled (for now).
        - test that QuickTime files with unsupported track types are handled correctly
        - test that broken video file produces an error

        * media/broken-video-expected.txt: Added.
        * media/broken-video.html: Added.
        * media/content/garbage.mp4: Added.
        * media/content/unsupported_track.mov: Added.
        * media/unsupported-rtsp-expected.txt: Added.
        * media/unsupported-rtsp.html: Added.
        * media/unsupported-tracks-expected.txt: Added.
        * media/unsupported-tracks.html: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@29547 268f45cc-cd09-0410-ab3c-d52691b4dbfc

12 files changed:
LayoutTests/ChangeLog
LayoutTests/media/broken-video-expected.txt [new file with mode: 0644]
LayoutTests/media/broken-video.html [new file with mode: 0644]
LayoutTests/media/content/garbage.mp4 [new file with mode: 0644]
LayoutTests/media/content/unsupported_track.mov [new file with mode: 0644]
LayoutTests/media/unsupported-rtsp-expected.txt [new file with mode: 0644]
LayoutTests/media/unsupported-rtsp.html [new file with mode: 0644]
LayoutTests/media/unsupported-tracks-expected.txt [new file with mode: 0644]
LayoutTests/media/unsupported-tracks.html [new file with mode: 0644]
WebCore/ChangeLog
WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h
WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm

index 15eef4e..05aae36 100644 (file)
@@ -1,3 +1,25 @@
+2008-01-16  Antti Koivisto  <antti@apple.com>
+
+        Reviewed by Adele.
+        
+        Tests for <rdar://problem/5605682>
+        Disallow streaming protocols for media elements
+        and <rdar://problem/5668711>
+        Limit the container and codec types that the <video> tag supports
+        
+        - test that rtsp: protocol is disabled (for now).
+        - test that QuickTime files with unsupported track types are handled correctly
+        - test that broken video file produces an error
+
+        * media/broken-video-expected.txt: Added.
+        * media/broken-video.html: Added.
+        * media/content/garbage.mp4: Added.
+        * media/content/unsupported_track.mov: Added.
+        * media/unsupported-rtsp-expected.txt: Added.
+        * media/unsupported-rtsp.html: Added.
+        * media/unsupported-tracks-expected.txt: Added.
+        * media/unsupported-tracks.html: Added.
+
 2008-01-16  Cameron Zwarich  <cwzwarich@uwaterloo.ca>
 
         Reviewed by Maciej.
diff --git a/LayoutTests/media/broken-video-expected.txt b/LayoutTests/media/broken-video-expected.txt
new file mode 100644 (file)
index 0000000..4715f66
--- /dev/null
@@ -0,0 +1,6 @@
+Test that QuickTime file with broken content generates an error.
+
+EVENT(error)
+TEST(video.error) OK
+END OF TEST
+
diff --git a/LayoutTests/media/broken-video.html b/LayoutTests/media/broken-video.html
new file mode 100644 (file)
index 0000000..aa83375
--- /dev/null
@@ -0,0 +1,10 @@
+<video controls></video>
+<p>Test that QuickTime file with broken content generates an error.<p>
+<script src=video-test.js></script>
+<script>
+video.src = "content/garbage.mp4";
+waitForEvent("error", function () {
+    test("video.error");
+    endTest();
+});
+</script>
diff --git a/LayoutTests/media/content/garbage.mp4 b/LayoutTests/media/content/garbage.mp4
new file mode 100644 (file)
index 0000000..f4b9fcb
--- /dev/null
@@ -0,0 +1 @@
+moov This is garbage!
diff --git a/LayoutTests/media/content/unsupported_track.mov b/LayoutTests/media/content/unsupported_track.mov
new file mode 100644 (file)
index 0000000..c05288c
--- /dev/null
@@ -0,0 +1 @@
+rtsptextrtsp://a2047.v1411b.c1411.g.vq.akamaistream.net/5/2047/1411/2_h264_650/1a1a1ae454c430950065de4cbb2f94c226950c7ae655b61a48a91475e243acda3dac194879adde0f/wwdc_2006_2_650.mov
diff --git a/LayoutTests/media/unsupported-rtsp-expected.txt b/LayoutTests/media/unsupported-rtsp-expected.txt
new file mode 100644 (file)
index 0000000..3c1b2b8
--- /dev/null
@@ -0,0 +1,7 @@
+Test that QuickTime file with RTSP URL generates a load error.
+
+EVENT(error)
+TEST(video.error) OK
+TEST(video.error.code = MediaError.MEDIA_ERR_NETWORK) OK
+END OF TEST
+
diff --git a/LayoutTests/media/unsupported-rtsp.html b/LayoutTests/media/unsupported-rtsp.html
new file mode 100644 (file)
index 0000000..51d3f8d
--- /dev/null
@@ -0,0 +1,11 @@
+<video controls></video>
+<p>Test that QuickTime file with RTSP URL generates a load error.<p>
+<script src=video-test.js></script>
+<script>
+video.src = "rtsp://a2047.v1411b.c1411.g.vq.akamaistream.net/5/2047/1411/2_h264_650/1a1a1ae454c430950065de4cbb2f94c226950c7ae655b61a48a91475e243acda3dac194879adde0f/wwdc_2006_2_650.mov";
+waitForEvent("error", function () {
+    test("video.error");
+    test("video.error.code = MediaError.MEDIA_ERR_NETWORK");
+    endTest();
+});
+</script>
diff --git a/LayoutTests/media/unsupported-tracks-expected.txt b/LayoutTests/media/unsupported-tracks-expected.txt
new file mode 100644 (file)
index 0000000..f5a18be
--- /dev/null
@@ -0,0 +1,6 @@
+Test that QuickTime file with unsupported track types only generates an error.
+
+EVENT(error)
+TEST(video.error) OK
+END OF TEST
+
diff --git a/LayoutTests/media/unsupported-tracks.html b/LayoutTests/media/unsupported-tracks.html
new file mode 100644 (file)
index 0000000..0e4ee5c
--- /dev/null
@@ -0,0 +1,10 @@
+<video controls></video>
+<p>Test that QuickTime file with unsupported track types only generates an error.<p>
+<script src=video-test.js></script>
+<script>
+video.src = "content/unsupported_track.mp4";
+waitForEvent("error", function () {
+    test("video.error");
+    endTest();
+});
+</script>
index 611a5ae..c7e7c70 100644 (file)
@@ -1,3 +1,29 @@
+2008-01-16  Antti Koivisto  <antti@apple.com>
+
+        Reviewed by Adele.
+        
+        OS X fix for <rdar://problem/5605682>
+        Disallow streaming protocols for media elements
+        and <rdar://problem/5668711>
+        Limit the container and codec types that the <video> tag supports
+        
+        - Disable unsupported QuickTime tracks types. 
+        - Disallow streaming protocols (for now).
+        - Set QTMovie QTMoviePreventExternalURLLinksAttribute and QTSecurityPolicyNoCrossSiteAttribute 
+          to limit QuickTime's access to external resources.
+        
+        Windows patch coming up.
+
+        Tests: media/broken-video.html
+               media/unsupported-rtsp.html
+               media/unsupported-tracks.html
+
+        * platform/graphics/mac/MediaPlayerPrivateQTKit.h:
+        * platform/graphics/mac/MediaPlayerPrivateQTKit.mm:
+        (WebCore::MediaPlayerPrivate::createQTMovie):
+        (WebCore::MediaPlayerPrivate::updateStates):
+        (WebCore::MediaPlayerPrivate::disableUnsupportedTracks):
+
 2008-01-16  Rodney Dawes  <dobey@wayofthemonkey.com>
 
         Reviewed by Alp Toker.
index f38f10d..83c6ee2 100644 (file)
@@ -112,6 +112,7 @@ private:
     void endPointTimerFired(Timer<MediaPlayerPrivate>*);
     float maxTimeLoaded() const;
     void startEndPointTimerIfNeeded();
+    void disableUnsupportedTracks(unsigned& enabledTrackCount);
 
     MediaPlayer* m_player;
     RetainPtr<QTMovie> m_qtMovie;
index 2b8a392..f2388d7 100644 (file)
@@ -55,32 +55,50 @@ SOFT_LINK(QTKit, QTMakeTime, QTTime, (long long timeValue, long timeScale), (tim
 SOFT_LINK_CLASS(QTKit, QTMovie)
 SOFT_LINK_CLASS(QTKit, QTMovieView)
 
+SOFT_LINK_POINTER(QTKit, QTMediaTypeAttribute, NSString *)
+SOFT_LINK_POINTER(QTKit, QTMediaTypeBase, NSString *)
+SOFT_LINK_POINTER(QTKit, QTMediaTypeSound, NSString *)
+SOFT_LINK_POINTER(QTKit, QTMediaTypeText, NSString *)
+SOFT_LINK_POINTER(QTKit, QTMediaTypeVideo, NSString *)
 SOFT_LINK_POINTER(QTKit, QTMovieDataSizeAttribute, NSString *)
 SOFT_LINK_POINTER(QTKit, QTMovieDidEndNotification, NSString *)
 SOFT_LINK_POINTER(QTKit, QTMovieHasVideoAttribute, NSString *)
+SOFT_LINK_POINTER(QTKit, QTMovieIsActiveAttribute, NSString *)
 SOFT_LINK_POINTER(QTKit, QTMovieLoadStateAttribute, NSString *)
 SOFT_LINK_POINTER(QTKit, QTMovieLoadStateDidChangeNotification, NSString *)
 SOFT_LINK_POINTER(QTKit, QTMovieNaturalSizeAttribute, NSString *)
+SOFT_LINK_POINTER(QTKit, QTMoviePreventExternalURLLinksAttribute, NSString *)
 SOFT_LINK_POINTER(QTKit, QTMovieRateDidChangeNotification, NSString *)
 SOFT_LINK_POINTER(QTKit, QTMovieSizeDidChangeNotification, NSString *)
 SOFT_LINK_POINTER(QTKit, QTMovieTimeDidChangeNotification, NSString *)
 SOFT_LINK_POINTER(QTKit, QTMovieTimeScaleAttribute, NSString *)
+SOFT_LINK_POINTER(QTKit, QTMovieURLAttribute, NSString *)
 SOFT_LINK_POINTER(QTKit, QTMovieVolumeDidChangeNotification, NSString *)
+SOFT_LINK_POINTER(QTKit, QTSecurityPolicyNoCrossSiteAttribute, NSString *)
 
 #define QTMovie getQTMovieClass()
 #define QTMovieView getQTMovieViewClass()
 
+#define QTMediaTypeAttribute getQTMediaTypeAttribute()
+#define QTMediaTypeBase getQTMediaTypeBase()
+#define QTMediaTypeSound getQTMediaTypeSound()
+#define QTMediaTypeText getQTMediaTypeText()
+#define QTMediaTypeVideo getQTMediaTypeVideo()
 #define QTMovieDataSizeAttribute getQTMovieDataSizeAttribute()
 #define QTMovieDidEndNotification getQTMovieDidEndNotification()
 #define QTMovieHasVideoAttribute getQTMovieHasVideoAttribute()
+#define QTMovieIsActiveAttribute getQTMovieIsActiveAttribute()
 #define QTMovieLoadStateAttribute getQTMovieLoadStateAttribute()
 #define QTMovieLoadStateDidChangeNotification getQTMovieLoadStateDidChangeNotification()
 #define QTMovieNaturalSizeAttribute getQTMovieNaturalSizeAttribute()
+#define QTMoviePreventExternalURLLinksAttribute getQTMoviePreventExternalURLLinksAttribute()
 #define QTMovieRateDidChangeNotification getQTMovieRateDidChangeNotification()
 #define QTMovieSizeDidChangeNotification getQTMovieSizeDidChangeNotification()
 #define QTMovieTimeDidChangeNotification getQTMovieTimeDidChangeNotification()
 #define QTMovieTimeScaleAttribute getQTMovieTimeScaleAttribute()
+#define QTMovieURLAttribute getQTMovieURLAttribute()
 #define QTMovieVolumeDidChangeNotification getQTMovieVolumeDidChangeNotification()
+#define QTSecurityPolicyNoCrossSiteAttribute getQTSecurityPolicyNoCrossSiteAttribute()
 
 // Older versions of the QTKit header don't have these constants.
 #if !defined QTKIT_VERSION_MAX_ALLOWED || QTKIT_VERSION_MAX_ALLOWED <= QTKIT_VERSION_7_0
@@ -143,8 +161,20 @@ void MediaPlayerPrivate::createQTMovie(const String& url)
 {
     [[NSNotificationCenter defaultCenter] removeObserver:m_objcObserver.get()];
     
+    m_qtMovie = 0;
+    
+    // Disable streaming support for now. 
+    if (url.startsWith("rtsp:"))
+        return;
+    
+    NSDictionary* movieAttributes = [NSDictionary dictionaryWithObjectsAndKeys:
+                                     KURL(url.deprecatedString()).getNSURL(), QTMovieURLAttribute,
+                                     [NSNumber numberWithBool:YES], QTMoviePreventExternalURLLinksAttribute,
+                                     [NSNumber numberWithBool:YES], QTSecurityPolicyNoCrossSiteAttribute,
+                                     nil];
+    
     NSError* error = nil;
-    m_qtMovie.adoptNS([[QTMovie alloc] initWithURL:KURL(url.deprecatedString()).getNSURL() error:&error]);
+    m_qtMovie.adoptNS([[QTMovie alloc] initWithAttributes:movieAttributes error:&error]);
     
     // FIXME: Find a proper way to detect streaming content.
     m_isStreaming = url.startsWith("rtsp:");
@@ -515,7 +545,16 @@ void MediaPlayerPrivate::updateStates()
     MediaPlayer::NetworkState oldNetworkState = m_networkState;
     MediaPlayer::ReadyState oldReadyState = m_readyState;
     
-    long loadState = m_qtMovie ? [[m_qtMovie.get() attributeForKey:QTMovieLoadStateAttribute] longValue] : -1;
+    long loadState = m_qtMovie ? [[m_qtMovie.get() attributeForKey:QTMovieLoadStateAttribute] longValue] : static_cast<long>(QTMovieLoadStateError);
+    
+    if (loadState >= QTMovieLoadStateLoaded && m_networkState < MediaPlayer::LoadedMetaData) {
+        unsigned enabledTrackCount;
+        disableUnsupportedTracks(enabledTrackCount);
+        // FIXME: We should differentiate between load errors and decode errors <rdar://problem/5605692>
+        if (!enabledTrackCount)
+            loadState = QTMovieLoadStateError;
+    }
+    
     // "Loaded" is reserved for fully buffered movies, never the case when streaming
     if (loadState >= QTMovieLoadStateComplete && !m_isStreaming) {
         if (m_networkState < MediaPlayer::Loaded)
@@ -533,7 +572,7 @@ void MediaPlayerPrivate::updateStates()
         if (m_networkState < MediaPlayer::LoadedMetaData)
             m_networkState = MediaPlayer::LoadedMetaData;
         m_readyState = MediaPlayer::DataUnavailable;
-    } else if (loadState >= 0) {
+    } else if (loadState > QTMovieLoadStateError) {
         if (m_networkState < MediaPlayer::Loading)
             m_networkState = MediaPlayer::Loading;
         m_readyState = MediaPlayer::DataUnavailable;        
@@ -660,6 +699,92 @@ bool MediaPlayerPrivate::isAvailable()
     }
     return true;
 }
+    
+void MediaPlayerPrivate::disableUnsupportedTracks(unsigned& enabledTrackCount)
+{
+    if (!m_qtMovie) {
+        enabledTrackCount = 0;
+        return;
+    }
+    
+    static HashSet<String>* allowedTrackTypes = 0;
+    if (!allowedTrackTypes) {
+        allowedTrackTypes = new HashSet<String>;
+        allowedTrackTypes->add(QTMediaTypeVideo);
+        allowedTrackTypes->add(QTMediaTypeSound);
+        allowedTrackTypes->add(QTMediaTypeText);
+        allowedTrackTypes->add(QTMediaTypeBase);
+        allowedTrackTypes->add("clcp");
+        allowedTrackTypes->add("sbtl");
+    }
+    
+    NSArray *tracks = [m_qtMovie.get() tracks];
+    
+    unsigned trackCount = [tracks count];
+    enabledTrackCount = trackCount;
+    for (unsigned trackIndex = 0; trackIndex < trackCount; trackIndex++)
+    {
+        // Grab the track at the current index. If there isn't one there, then
+        // we can move onto the next one.
+        QTTrack *track = [tracks objectAtIndex:trackIndex];
+        if (!track)
+            continue;
+        
+        // Check to see if the track is disabled already, we should move along.
+        // We don't need to re-disable it.
+        if (![track isEnabled])
+            continue;
+        
+        // Grab the track's media. We're going to check to see if we need to
+        // disable the tracks. They could be unsupported. <rdar://problem/4983892>
+        QTMedia *trackMedia = [track media];
+        if (!trackMedia)
+            continue;
+        
+        // Grab the media type for this track.
+        NSString *mediaType = [trackMedia attributeForKey:QTMediaTypeAttribute];
+        if (!mediaType)
+            continue;
+        
+        // Test whether the media type is in our white list.
+        if (!allowedTrackTypes->contains(mediaType)) {
+            // If this track type is not allowed, then we need to disable it.
+            [track setEnabled:NO];
+            --enabledTrackCount;
+        }
+        
+        // Disable chapter tracks. These are most likely to lead to trouble, as
+        // they will be composited under the video tracks, forcing QT to do extra
+        // work.
+        QTTrack *chapterTrack = [track performSelector:@selector(chapterlist)];
+        if (!chapterTrack)
+            continue;
+        
+        // Try to grab the media for the track.
+        QTMedia *chapterMedia = [chapterTrack media];
+        if (!chapterMedia)
+            continue;
+        
+        // Grab the media type for this track.
+        id chapterMediaType = [chapterMedia attributeForKey:QTMediaTypeAttribute];
+        if (!chapterMediaType)
+            continue;
+        
+        // Check to see if the track is a video track. We don't care about
+        // other non-video tracks.
+        if (![chapterMediaType isEqual:QTMediaTypeVideo])
+            continue;
+        
+        // Check to see if the track is already disabled. If it is, we
+        // should move along.
+        if (![chapterTrack isEnabled])
+            continue;
+        
+        // Disable the evil, evil track.
+        [chapterTrack setEnabled:NO];
+        --enabledTrackCount;
+    }
+}
 
 }