Bug 186353

Summary: iOS 11.4 breaks video playback in Cordova apps
Product: WebKit Reporter: Ashley Gullen <ashley>
Component: WebKit Misc.Assignee: Nobody <webkit-unassigned>
Status: NEW ---    
Severity: Major CC: beidson, bfulgham, cdumez, dbates, eric.carlson, jer.noble, webkit-bug-importer, youennf
Priority: P2 Keywords: InRadar
Version: Safari 11   
Hardware: iPhone / iPad   
OS: iOS 11   

Description Ashley Gullen 2018-06-06 09:21:58 PDT
Cordova apps on iOS run on the file:// protocol in WKWebView. Because there is still no solution to issue 154916, some subresources unnecessarily count as cross-origin. One example is rendering video in WebGL. The video must count as same-origin to be able to upload to a texture.

To work around this, our framework (construct.net) previously would use cordova-plugin-file to read the video file as a blob, use URL.createObjectURL(blob), and then assign that to the video source. However as of iOS 11.4, this now appears to create a blob with an origin of 'null', which *still* counts as a cross-origin resource. Therefore video uploads to textures fail with a SecurityError.

As a result all existing iOS apps made using our framework are no longer able to display video in iOS 11.4. I cannot even find any work around to make the video count as same-origin, so I don't even know if we can update our framework.

Please at least allow video playback from a blob URL in this case.

To demonstrate the problem, here is a Cordova iOS project that plays video in a WebGL context: https://www.dropbox.com/s/izhjf84abzvztqb/ios-local-video-test.zip?dl=0
The video plays and the audio track can be heard, but it does not appear, because it is throwing a SecurityError every frame trying to update the texture.
Comment 1 Radar WebKit Bug Importer 2018-06-07 11:47:30 PDT
<rdar://problem/40904329>
Comment 2 Brent Fulgham 2018-06-15 08:44:37 PDT
Could you attach some logging showing the security exceptions being generated? We are not familiar with Cordova building and debugging, so need some additional context.

Is it possible to create a test case outside of Cordova that demonstrates the CORS issue you think is happening?
Comment 3 Brent Fulgham 2018-06-15 11:22:23 PDT
This behavior change started with Bug 178573, where we began supporting createImageBitmap. That caused this test app to not display audio or video.

Later, in Bug 183247, audio began working again when Blob support was added.

I think we actually have an issue where an underling Cordova component sees that 'createImageBitmap' is available and tries to use it.

Unfortunately, createImageBitmap with ImageData is not currently implemented, which causes us to return a blank ImageBitmap.

I don't know how to do further debugging in Cordova, but I think this is just a compatibility issue due to the incomplete createImageBitmap implementation.
Comment 4 Ashley Gullen 2018-06-19 07:55:06 PDT
The log simply says "SecurityError: The operation is insecure." It's logged from a catch handler caused by an exception thrown in the following line:

gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, formatspec.format, formatspec.type, data);

where 'data' is a <video> whose src is a blob URL similar to "blob:null/...". The error appears to be due to the fact the video is considered a cross-origin video, since it has a 'null' origin, even though it was created by script in the same document - presumably a change to the file: protocol that the page is running on.

None of this code uses ImageBitmap at all. Does Safari use ImageBitmap internally for the texSubImage2D call? If not, then I believe that ImageBitmap is not involved in this.

If you want a repro that doesn't involve Cordova, it's simple: make an app that loads a HTML file from the bundle in a WKWebView. (This is the basis of a Cordova app.) In that HTML file, try to load a video and upload it to a WebGL texture. Any existing "video playback in WebGL" sample should do, e.g.: https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/Tutorial/Animating_textures_in_WebGL

You'll quickly run in to a bunch of difficult problems:
- if you just set the video src to the video file in the bundle, it counts as cross-origin so blocks the texture upload
- XMLHttpRequest fails since it counts as cross-origin
- fetch() fails since it is not supported on file://
- you can't host all the files on a HTTP server, since you can't pick a fixed port that is guaranteed to be free, and if you pick a varying port, then the storage origin changes so you keep losing saved data
- using Cordova APIs, or otherwise calling in to native code, can read the file and return it to JavaScript as a Blob. This used to work. Now it's broken again due to the problem reported here.

It does seem like nobody has ever really thought about how to properly support apps like this. The CORS restrictions are incredibly severe so you have to use hacks to work around them; then those hacks occasionally break with iOS updates, causing existing apps to break. It would be great if there was better support for this in general so WKWebView was easier to use and we didn't have to risk apps breaking when things are changed.