Title: [196827] trunk/Source/WebCore
Revision
196827
Author
[email protected]
Date
2016-02-19 11:46:19 -0800 (Fri, 19 Feb 2016)

Log Message

[Mac] CORS-compliant videos throw security errors when painting to Canvas
https://bugs.webkit.org/show_bug.cgi?id=154188
<rdar://problem/22959556>

Reviewed by Alex Christensen.

Pass the CORS access check results from WebCoreNSURLSession to it's client,
MediaPlayerPrivateAVFoundationObjC.

* WebCore.xcodeproj/project.pbxproj:
* platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.h:
* platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm:
(WebCore::MediaPlayerPrivateAVFoundationObjC::didPassCORSAccessCheck): Ask the WebCoreNSURLSession.
* platform/network/cocoa/WebCoreNSURLSession.h:
* platform/network/cocoa/WebCoreNSURLSession.mm:
(-[WebCoreNSURLSession task:didReceiveCORSAccessCheckResult:]): Conditionally set _corsResults.
(-[WebCoreNSURLSession didPassCORSAccessChecks]): Return _corsResults.
(WebCoreNSURLSessionDataTaskClient::accessControlCheckFailed): Call -resource:accessControlCheckFailedWithError:.
(WebCoreNSURLSessionDataTaskClient::loadFailed): Call -resource:loadFailedWithError:.
(-[WebCoreNSURLSessionDataTask resource:receivedResponse:]): Set _response within the delegate queue.
(-[WebCoreNSURLSessionDataTask _resource:loadFinishedWithError:]): Renamed from resourceFinished:
(-[WebCoreNSURLSessionDataTask resource:accessControlCheckFailedWithError:]): Ditto.
(-[WebCoreNSURLSessionDataTask resource:loadFailedWithError:]): Ditto.
(-[WebCoreNSURLSessionDataTask resourceFinished:]): Ditto.

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (196826 => 196827)


--- trunk/Source/WebCore/ChangeLog	2016-02-19 19:12:51 UTC (rev 196826)
+++ trunk/Source/WebCore/ChangeLog	2016-02-19 19:46:19 UTC (rev 196827)
@@ -1,3 +1,30 @@
+2016-02-12  Jer Noble  <[email protected]>
+
+        [Mac] CORS-compliant videos throw security errors when painting to Canvas
+        https://bugs.webkit.org/show_bug.cgi?id=154188
+        <rdar://problem/22959556>
+
+        Reviewed by Alex Christensen.
+
+        Pass the CORS access check results from WebCoreNSURLSession to it's client,
+        MediaPlayerPrivateAVFoundationObjC.
+
+        * WebCore.xcodeproj/project.pbxproj:
+        * platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.h:
+        * platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm:
+        (WebCore::MediaPlayerPrivateAVFoundationObjC::didPassCORSAccessCheck): Ask the WebCoreNSURLSession.
+        * platform/network/cocoa/WebCoreNSURLSession.h:
+        * platform/network/cocoa/WebCoreNSURLSession.mm:
+        (-[WebCoreNSURLSession task:didReceiveCORSAccessCheckResult:]): Conditionally set _corsResults.
+        (-[WebCoreNSURLSession didPassCORSAccessChecks]): Return _corsResults.
+        (WebCoreNSURLSessionDataTaskClient::accessControlCheckFailed): Call -resource:accessControlCheckFailedWithError:.
+        (WebCoreNSURLSessionDataTaskClient::loadFailed): Call -resource:loadFailedWithError:.
+        (-[WebCoreNSURLSessionDataTask resource:receivedResponse:]): Set _response within the delegate queue.
+        (-[WebCoreNSURLSessionDataTask _resource:loadFinishedWithError:]): Renamed from resourceFinished:
+        (-[WebCoreNSURLSessionDataTask resource:accessControlCheckFailedWithError:]): Ditto.
+        (-[WebCoreNSURLSessionDataTask resource:loadFailedWithError:]): Ditto.
+        (-[WebCoreNSURLSessionDataTask resourceFinished:]): Ditto.
+
 2016-02-19  Chris Dumez  <[email protected]>
 
         Unreviewed build fix.

Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.h (196826 => 196827)


--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.h	2016-02-19 19:12:51 UTC (rev 196826)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.h	2016-02-19 19:46:19 UTC (rev 196827)
@@ -216,7 +216,8 @@
 
     virtual void updateVideoLayerGravity() override;
 
-    virtual bool hasSingleSecurityOrigin() const override;
+    bool hasSingleSecurityOrigin() const override;
+    bool didPassCORSAccessCheck() const override;
 
     MediaTime getStartDate() const override;
 

Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm (196826 => 196827)


--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm	2016-02-19 19:12:51 UTC (rev 196826)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm	2016-02-19 19:46:19 UTC (rev 196827)
@@ -917,7 +917,7 @@
     AVAssetResourceLoader *resourceLoader = m_avAsset.get().resourceLoader;
     [resourceLoader setDelegate:m_loaderDelegate.get() queue:globalLoaderDelegateQueue()];
 
-#if PLATFORM(IOS) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101100
+#if PLATFORM(IOS) || __MAC_OS_X_VERSION_MIN_REQUIRED > 101100
     if (Settings::isAVFoundationNSURLSessionEnabled()
         && [resourceLoader respondsToSelector:@selector(setURLSession:)]
         && [resourceLoader respondsToSelector:@selector(URLSessionDataDelegate)]
@@ -2163,6 +2163,21 @@
     return resolvedOrigin.get().isSameSchemeHostPort(&requestedOrigin.get());
 }
 
+bool MediaPlayerPrivateAVFoundationObjC::didPassCORSAccessCheck() const
+{
+#if PLATFORM(IOS) || __MAC_OS_X_VERSION_MIN_REQUIRED > 101100
+    AVAssetResourceLoader *resourceLoader = m_avAsset.get().resourceLoader;
+    if (!Settings::isAVFoundationNSURLSessionEnabled()
+        || ![resourceLoader respondsToSelector:@selector(URLSession)])
+        return false;
+
+    WebCoreNSURLSession *session = (WebCoreNSURLSession *)resourceLoader.URLSession;
+    if ([session respondsToSelector:@selector(didPassCORSAccessChecks)])
+        return session.didPassCORSAccessChecks;
+#endif
+    return false;
+}
+
 #if HAVE(AVFOUNDATION_VIDEO_OUTPUT)
 void MediaPlayerPrivateAVFoundationObjC::createVideoOutput()
 {

Modified: trunk/Source/WebCore/platform/network/cocoa/WebCoreNSURLSession.h (196826 => 196827)


--- trunk/Source/WebCore/platform/network/cocoa/WebCoreNSURLSession.h	2016-02-19 19:12:51 UTC (rev 196826)
+++ trunk/Source/WebCore/platform/network/cocoa/WebCoreNSURLSession.h	2016-02-19 19:46:19 UTC (rev 196827)
@@ -48,6 +48,12 @@
 class WebCoreNSURLSessionDataTaskClient;
 }
 
+enum class WebCoreNSURLSessionCORSAccessCheckResults {
+    Unknown,
+    Pass,
+    Fail,
+};
+
 NS_ASSUME_NONNULL_BEGIN
 
 WEBCORE_EXPORT @interface WebCoreNSURLSession : NSObject {
@@ -59,12 +65,14 @@
     BOOL _invalidated;
     NSUInteger _nextTaskIdentifier;
     OSObjectPtr<dispatch_queue_t> _internalQueue;
+    WebCoreNSURLSessionCORSAccessCheckResults _corsResults;
 }
 - (id)initWithResourceLoader:(WebCore::PlatformMediaResourceLoader&)loader delegate:(id<NSURLSessionTaskDelegate>)delegate delegateQueue:(NSOperationQueue*)queue;
 @property (readonly, retain) NSOperationQueue *delegateQueue;
 @property (nullable, readonly, retain) id <NSURLSessionDelegate> delegate;
 @property (readonly, copy) NSURLSessionConfiguration *configuration;
 @property (copy) NSString *sessionDescription;
+@property (readonly) BOOL didPassCORSAccessChecks;
 - (void)finishTasksAndInvalidate;
 - (void)invalidateAndCancel;
 
@@ -97,7 +105,6 @@
 
 @interface WebCoreNSURLSessionDataTask : NSObject {
     WebCoreNSURLSession *_session;
-    std::unique_ptr<WebCore::WebCoreNSURLSessionDataTaskClient> _client;
     RefPtr<WebCore::PlatformMediaResource> _resource;
     RetainPtr<NSURLResponse> _response;
     NSUInteger _taskIdentifier;

Modified: trunk/Source/WebCore/platform/network/cocoa/WebCoreNSURLSession.mm (196826 => 196827)


--- trunk/Source/WebCore/platform/network/cocoa/WebCoreNSURLSession.mm	2016-02-19 19:12:51 UTC (rev 196826)
+++ trunk/Source/WebCore/platform/network/cocoa/WebCoreNSURLSession.mm	2016-02-19 19:46:19 UTC (rev 196827)
@@ -43,6 +43,7 @@
 @property (readwrite, retain) id<NSURLSessionTaskDelegate> delegate;
 - (void)taskCompleted:(WebCoreNSURLSessionDataTask *)task;
 - (void)addDelegateOperation:(void (^)(void))operation;
+- (void)task:(WebCoreNSURLSessionDataTask *)task didReceiveCORSAccessCheckResult:(BOOL)result;
 @end
 
 @interface WebCoreNSURLSessionDataTask ()
@@ -58,6 +59,8 @@
 - (void)resource:(PlatformMediaResource&)resource receivedResponse:(const ResourceResponse&)response;
 - (void)resource:(PlatformMediaResource&)resource receivedData:(const char*)data length:(int)length;
 - (void)resource:(PlatformMediaResource&)resource receivedRedirect:(const ResourceResponse&)response request:(ResourceRequest&)request;
+- (void)resource:(PlatformMediaResource&)resource accessControlCheckFailedWithError:(const ResourceError&)error;
+- (void)resource:(PlatformMediaResource&)resource loadFailedWithError:(const ResourceError&)error;
 - (void)resourceFinished:(PlatformMediaResource&)resource;
 @end
 
@@ -72,10 +75,12 @@
     if (!self)
         return nil;
 
+    ASSERT(_corsResults == WebCoreNSURLSessionCORSAccessCheckResults::Unknown);
+    ASSERT(!_invalidated);
+
     _loader = &loader;
     self.delegate = inDelegate;
     _queue = inQueue ? inQueue : [NSOperationQueue mainQueue];
-    _invalidated = NO;
     _internalQueue = adoptOSObject(dispatch_queue_create("WebCoreNSURLSession _internalQueue", DISPATCH_QUEUE_SERIAL));
 
     return self;
@@ -120,6 +125,15 @@
     });
 }
 
+- (void)task:(WebCoreNSURLSessionDataTask *)task didReceiveCORSAccessCheckResult:(BOOL)result
+{
+    UNUSED_PARAM(task);
+    if (!result)
+        _corsResults = WebCoreNSURLSessionCORSAccessCheckResults::Fail;
+    else if (_corsResults != WebCoreNSURLSessionCORSAccessCheckResults::Fail)
+        _corsResults = WebCoreNSURLSessionCORSAccessCheckResults::Pass;
+}
+
 #pragma mark - NSURLSession API
 @synthesize sessionDescription=_sessionDescription;
 @dynamic delegate;
@@ -151,6 +165,12 @@
     return *_loader;
 }
 
+@dynamic didPassCORSAccessChecks;
+- (BOOL)didPassCORSAccessChecks
+{
+    return _corsResults == WebCoreNSURLSessionCORSAccessCheckResults::Pass;
+}
+
 - (void)finishTasksAndInvalidate
 {
     _invalidated = YES;
@@ -298,6 +318,8 @@
     void redirectReceived(PlatformMediaResource&, ResourceRequest&, const ResourceResponse&) override;
     void dataSent(PlatformMediaResource&, unsigned long long, unsigned long long) override;
     void dataReceived(PlatformMediaResource&, const char* /* data */, int /* length */) override;
+    void accessControlCheckFailed(PlatformMediaResource&, const ResourceError&) override;
+    void loadFailed(PlatformMediaResource&, const ResourceError&) override;
     void loadFinished(PlatformMediaResource&) override;
 
 private:
@@ -324,6 +346,16 @@
     [m_task resource:resource receivedRedirect:response request:request];
 }
 
+void WebCoreNSURLSessionDataTaskClient::accessControlCheckFailed(PlatformMediaResource& resource, const ResourceError& error)
+{
+    [m_task resource:resource accessControlCheckFailedWithError:error];
+}
+
+void WebCoreNSURLSessionDataTaskClient::loadFailed(PlatformMediaResource& resource, const ResourceError& error)
+{
+    [m_task resource:resource loadFailedWithError:error];
+}
+
 void WebCoreNSURLSessionDataTaskClient::loadFinished(PlatformMediaResource& resource)
 {
     [m_task resourceFinished:resource];
@@ -473,11 +505,14 @@
 {
     ASSERT_UNUSED(resource, &resource == _resource);
     ASSERT(isMainThread());
-    _response = response.nsURLResponse();
+    [self.session task:self didReceiveCORSAccessCheckResult:resource.didPassAccessControlCheck()];
     self.countOfBytesExpectedToReceive = response.expectedContentLength();
     [self _setDefersLoading:YES];
+    RetainPtr<NSURLResponse> strongResponse { response.nsURLResponse() };
     RetainPtr<WebCoreNSURLSessionDataTask> strongSelf { self };
-    [self.session addDelegateOperation:[strongSelf] {
+    [self.session addDelegateOperation:[strongSelf, strongResponse] {
+        strongSelf->_response = strongResponse.get();
+
         id<NSURLSessionDataDelegate> dataDelegate = (id<NSURLSessionDataDelegate>)strongSelf.get().session.delegate;
         if (![dataDelegate respondsToSelector:@selector(URLSession:dataTask:didReceiveResponse:completionHandler:)]) {
             callOnMainThread([strongSelf] {
@@ -486,7 +521,7 @@
             return;
         }
 
-        [dataDelegate URLSession:(NSURLSession *)strongSelf.get().session dataTask:(NSURLSessionDataTask *)strongSelf.get() didReceiveResponse:strongSelf.get().response completionHandler:[strongSelf] (NSURLSessionResponseDisposition disposition) {
+        [dataDelegate URLSession:(NSURLSession *)strongSelf.get().session dataTask:(NSURLSessionDataTask *)strongSelf.get() didReceiveResponse:strongResponse.get() completionHandler:[strongSelf] (NSURLSessionResponseDisposition disposition) {
             if (disposition == NSURLSessionResponseCancel)
                 [strongSelf cancel];
             else if (disposition == NSURLSessionResponseAllow)
@@ -531,22 +566,36 @@
     // API, this can be implemented.
 }
 
-- (void)resourceFinished:(PlatformMediaResource&)resource
+- (void)_resource:(PlatformMediaResource&)resource loadFinishedWithError:(NSError *)error
 {
     ASSERT_UNUSED(resource, &resource == _resource);
-    self.state = NSURLSessionTaskStateCompleted;
-
     RetainPtr<WebCoreNSURLSessionDataTask> strongSelf { self };
-    [self.session addDelegateOperation:[strongSelf] {
+    RetainPtr<NSError> strongError { error };
+    [self.session addDelegateOperation:[strongSelf, strongError] {
         id<NSURLSessionTaskDelegate> delegate = (id<NSURLSessionTaskDelegate>)strongSelf.get().session.delegate;
         if ([delegate respondsToSelector:@selector(URLSession:task:didCompleteWithError:)])
-            [delegate URLSession:(NSURLSession *)strongSelf.get().session task:(NSURLSessionDataTask *)strongSelf.get() didCompleteWithError:nil];
+            [delegate URLSession:(NSURLSession *)strongSelf.get().session task:(NSURLSessionDataTask *)strongSelf.get() didCompleteWithError:strongError.get()];
 
         callOnMainThread([strongSelf] {
             [strongSelf.get().session taskCompleted:strongSelf.get()];
         });
     }];
 }
+
+- (void)resource:(PlatformMediaResource&)resource accessControlCheckFailedWithError:(const ResourceError&)error
+{
+    [self _resource:resource loadFinishedWithError:error.nsError()];
+}
+
+- (void)resource:(PlatformMediaResource&)resource loadFailedWithError:(const ResourceError&)error
+{
+    [self _resource:resource loadFinishedWithError:error.nsError()];
+}
+
+- (void)resourceFinished:(PlatformMediaResource&)resource
+{
+    [self _resource:resource loadFinishedWithError:nil];
+}
 @end
 
 #endif // PLATFORM(IOS) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101100
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to