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