WebRTC getUserMedia promise api support in Chrome - google-chrome

Does chrome support promise based APIs for WebRTC? I am not able to get the getUserMedia() promised based API working in Chrome.
<!DOCTYPE html>
<html>
<head>
<title> Mitel WebRTC client </title>
<script src="https://webrtc.github.io/adapter/adapter-latest.js"></script>
<script src='dist/webrtc.min.js'></script>
<script type="text/javascript">
function startUp() {
var options = {
audio: true,
video: true
};
if (getUserMedia) {
getUserMedia(options)
.then(function (stream) {
console.log("Acquired audio and video!");
})
.catch(function (err) {
console.log(err.name + ": " + err.message);
});
} else {
alert("WebRTC not supported on this browser");
}
}
</script>
</head>
<body onload="startUp();">
<h1>WebRTC Promise API Client Application</h1>
</body>
</html>
On the console, I see the following error
This appears to be Chrome
adapter-latest.js:32 chrome: {"audio":true,"video":true}
adapter-latest.js:410 Uncaught TypeError: Failed to execute 'webkitGetUserMedia' on 'Navigator': The callback provided as parameter 2 is not a function.
I want to make use of promise based API. Am I missing something?

It is not implemented yet in Chrome, but it works there if you use the official adapter.js WebRTC polyfill: https://jsfiddle.net/srn9db4h/
var constraints = { video: true, audio: true };
navigator.mediaDevices.getUserMedia(constraints)
.then(stream => video.srcObject = stream)
.catch(e => console.error(e));
Firefox and Edge support it natively FWIW.
Update: Chrome (50) appears to support this now. And Chrome 52 even supports srcObject.

To access navigator.mediaDevices you must to connect your site with HTTPS connection. There are no access this feature with HTTP.
https://developers.google.com/web/fundamentals/media/capturing-images/
Warning: Direct access to the camera is a powerful feature. It requires consent from the user, and your site MUST be on a secure origin (HTTPS).

Although this is not recommended but still you can try this to test your project by disabling security for media.
chrome://flags/#unsafely-treat-insecure-origin-as-secure
you can add your IP and chrome will treat it as secure.

You can also get this error if you're running Chrome your app in http. If so, you should run your app as https. Only localhost urls with http are supported by Chrome.
`http://jsfiddle.net/jib1/srn9db4h/ `
// not working
`https://jsfiddle.net/jib1/srn9db4h/`
//working with https

Related

Is cross-origin postMessage broken in IE10?

I'm trying to make a trivial postMessage example work...
in IE10
between windows/tabs (vs. iframes)
across origins
Remove any one of these conditions, and things work fine :-)
But as far as I can tell, between-window postMessage only appears to work in IE10 when both windows share an origin. (Well, in fact -- and weirdly -- the behavior is slightly more permissive than that: two different origins that share a host seem to work, too).
Is this a documented bug? Any workarounds or other advice?
(Note: This question touches on the issues, but its answer is about IE8 and IE9 -- not 10)
More details + example...
launcher page demo
<!DOCTYPE html>
<html>
<script>
window.addEventListener("message", function(e){
console.log("Received message: ", e);
}, false);
</script>
<button onclick="window.open('http://jsbin.com/ameguj/1');">
Open new window
</button>
</html>
launched page demo
<!DOCTYPE html>
<html>
<script>
window.opener.postMessage("Ahoy!", "*");
</script>
</html>
This works at: http://jsbin.com/ahuzir/1 -- because both pages are hosted at the same origin (jsbin.com). But move the second page anywhere else, and it fails in IE10.
I was mistaken when I originally posted this answer: it doesn't actually work in IE10. Apparently people have found this useful for other reasons so I'm leaving it up for posterity. Original answer below:
Worth noting: the link in that answer you linked to states that postMessage isn't cross origin for separate windows in IE8 and IE9 -- however, it was also written in 2009, before IE10 came around. So I wouldn't take that as an indication that it's fixed in IE10.
As for postMessage itself, http://caniuse.com/#feat=x-doc-messaging notably indicates that it's still broken in IE10, which seems to match up with your demo. The caniuse page links to this article, which contains a very relevant quote:
Internet Explorer 8+ partially supports cross-document messaging: it
currently works with iframes, but not new windows. Internet Explorer
10, however, will support MessageChannel. Firefox currently supports
cross-document messaging, but not MessageChannel.
So your best bet is probably to have a MessageChannel based codepath, and fallback to postMessage if that doesn't exist. It won't get you IE8/IE9 support, but at least it'll work with IE10.
Docs on MessageChannel: http://msdn.microsoft.com/en-us/library/windows/apps/hh441303.aspx
Create a proxy page on the same host as launcher. Proxy page has an iframe with source set to remote page. Cross-origin postMessage will now work in IE10 like so:
Remote page uses window.parent.postMessage to pass data to proxy page. As this uses iframes, it's supported by IE10
Proxy page uses window.opener.postMessage to pass data back to launcher page. As this is on same domain - there are no cross-origin issues. It can also directly call global methods on the launcher page if you don't want to use postMessage - eg. window.opener.someMethod(data)
Sample (all URLs are fictitous)
Launcher page at http://example.com/launcher.htm
<!DOCTYPE html>
<html>
<head>
<title>Test launcher page</title>
<link rel="stylesheet" href="/css/style.css" />
</head>
<body>
<script>
function log(msg) {
if (!msg) return;
var logger = document.getElementById('logger');
logger.value += msg + '\r\n';
}
function toJson(obj) {
return JSON.stringify(obj, null, 2);
}
function openProxy() {
var url = 'proxy.htm';
window.open(url, 'wdwProxy', 'location=no');
log('Open proxy: ' + url);
}
window.addEventListener('message', function(e) {
log('Received message: ' + toJson(e.data));
}, false);
</script>
<button onclick="openProxy();">Open remote</button> <br/>
<textarea cols="150" rows="20" id="logger"></textarea>
</body>
</html>
Proxy page at http://example.com/proxy.htm
<!DOCTYPE html>
<html>
<head>
<title>Proxy page</title>
<link rel="stylesheet" href="/css/style.css" />
</head>
<body>
<script>
function toJson(obj) {
return JSON.stringify(obj, null, 2);
}
window.addEventListener('message', function(e) {
console.log('Received message: ' + toJson(e.data));
window.opener.postMessage(e.data, '*');
window.close(self);
}, false);
</script>
<iframe src="http://example.net/remote.htm" frameborder="0" height="300" width="500" marginheight="0" marginwidth="0" scrolling="auto"></iframe>
</body>
</html>
Remote page at http://example.net/remote.htm
<!DOCTYPE html>
<html>
<head>
<title>Remote page</title>
<link rel="stylesheet" href="/css/style.css" />
</head>
<body>
<script>
function remoteSubmit() {
var data = {
message: document.getElementById('msg').value
};
window.parent.postMessage(data, '*');
}
</script>
<h2>Remote page</h2>
<input type="text" id="msg" placeholder="Type a message" /><button onclick="remoteSubmit();">Close</button>
</body>
</html>
== WORKING SOLUTION IN 2020 without iframe ==
Building on answer by tangle, I had success in IE11 [and emulated IE10 mode] using following snippet:
var submitWindow = window.open("/", "processingWindow");
submitWindow.location.href = 'about:blank';
submitWindow.location.href = 'remotePage to communicate with';
Then I was able to communicate using typical postMessage stack, I'm using one global static messenger in my scenario (although I don't suppose it's of any significance, I'm also attaching my messenger class)
var messagingProvider = {
_initialized: false,
_currentHandler: null,
_init: function () {
var self = this;
this._initialized = true;
var eventMethod = window.addEventListener ? "addEventListener" : "attachEvent";
var eventer = window[eventMethod];
var messageEvent = eventMethod == "attachEvent" ? "onmessage" : "message";
eventer(messageEvent, function (e) {
var callback = self._currentHandler;
if (callback != null) {
var key = e.message ? "message" : "data";
var data = e[key];
callback(data);
}
}, false);
},
post: function (target, message) {
target.postMessage(message, '*');
},
setListener: function (callback) {
if (!this._initialized) {
this._init();
}
this._currentHandler = callback;
}
}
No matter how hard I tried, I wasn't able to make things work on IE9 and IE8
My config where it's working:
IE version: 11.0.10240.16590, Update versions: 11.0.25 (KB3100773)
Building upon the answers by LyphTEC and Akrikos, another work-around is to create an <iframe> within a blank popup window, which avoids the need for a separate proxy page, since the blank popup has the same origin as its opener.
Launcher page at http://example.com/launcher.htm
<html>
<head>
<title>postMessage launcher</title>
<script>
function openWnd() {
var w = window.open("", "theWnd", "resizeable,status,width=400,height=300"),
i = w.document.createElement("iframe");
i.src = "http://example.net/remote.htm";
w.document.body.appendChild(i);
w.addEventListener("message", function (e) {
console.log("message from " + e.origin + ": " + e.data);
// Send a message back to the source
e.source.postMessage("reply", e.origin);
});
}
</script>
</head>
<body>
<h2>postMessage launcher</h2>
<p>click me</p>
</body>
</html>
Remote page at http://example.net/remote.htm
<html>
<head>
<title>postMessage remote</title>
<script>
window.addEventListener("message", function (e) {
alert("message from " + e.origin + ": " + e.data);
});
// Send a message to the parent window every 5 seconds
setInterval(function () {
window.parent.postMessage("hello", "*");
}, 5000);
</script>
</head>
<body>
<h2>postMessage remote</h2>
</body>
</html>
I'm not sure how fragile this is, but it is working in IE 11 and Firefox 40.0.3.
Right now, (2014-09-02), Your best bet is to use a proxy frame as noted in the msdn blog post that details a workaround for this issue: https://blogs.msdn.microsoft.com/ieinternals/2009/09/15/html5-implementation-issues-in-ie8-and-later/
Here's the working example: http://www.debugtheweb.com/test/xdm/origin/
You need to set up a proxy frame on your page that has the same origin as the popup. Send information from the popup to the proxy frame using window.opener.frames[0]. Then use postMessage from the proxy frame to the main page.
This solution involves adding the site to Internet Explore's Trusted Sites and not in the Local Intranet sites. I tested this solution in Windows 10/IE 11.0.10240.16384, Windows 10/Microsoft Edge 20.10240.16384.0 and Windows 7 SP1/IE 10.0.9200.17148. The page must not be included in the Intranet Zone.
So open Internet Explorer configuration (Tools > Internet Options > Security > Trusted Sites > Sites), and add the page, here I use * to match all the subdomains. Make sure the page isn't listed in the Local intranet sites (Tools > Internet Options > Security > Local Intranet > Sites > Advanced). Restart your browser and test again.
In Windows 10/Microsoft Edge you will find this configuration in Control Panel > Internet Options.
UPDATE
If this doesn't work you could try resetting all your settings in Tools > Internet Options > Advanced Settings > Reset Internet Explorer settings and then Reset: use it with caution! Then you will need to reboot your system. After that add the sites to the Trusted sites.
See in what zone your page is in File > Properties or using right click.
UPDATE
I am in a corporate intranet and sometimes it works and sometimes it doesn't (automatic configuration? I even started to blame the corporate proxy). In the end I used this solution https://stackoverflow.com/a/36630058/2692914.
This Q is old but this is what easyXDM is for, maybe check it out as a potential fallback when you detect a browser that does not support html5 .postMessage :
https://easyxdm.net/
It uses VBObject wrapper and all types of stuff you'd never want to have to deal with to send cross domain messages between windows or frames where window.postMessage fails for various IE versions (and edge maybe, still not sure 100% on the support Edge has but it seems to also need a workaround for .postMessage)
MessageChannel doesn't work for IE 9-11 between windows/tabs since it relies on postMessage, which is still broken in this scenario. The "best" workaround is to call a function through window.opener (ie. window.opener.somefunction("somedata") ).
Workaround in more detail here

Api empty output on client side

I am working on api of a script i recently coded.
on browser the output of the file is working fine see here : http://www.lilink.it/api.php?u=http://www.designzzz.com/&method=get_short_url
but if i do the calling on client side it returns empty. here is the code for client side :
<script type="text/javascript">
$(document).ready(function() {
// method 1
$.get('http://lilink.it/api.php', {method: 'get_short_url', u: 'http://www.blastingart.com/ayaz-malik'},
function(data){
alert(data.status + data.res);
}, "json"
);
// method 2
$.getJSON('http://lilink.it/api.php?method=get_short_url&u=http://www.blastingart.com/ayaz-malik', function(data) {
if (data.status == 1) {
alert(data.status + data.res);
}
});
});
</script>
Probably, you are trying to make a cross-domain request. Cross domain requests are denied in modern web browsers for security reasons. But it's possible to implement them using special techniques. See:
http://usejquery.com/posts/the-jquery-cross-domain-ajax-guide
You probably have problem about the Same Origin Policy: more info here

How to get the root folder in Chrome Extensions?

I am developing a Chrome Extesion for the first time and I am following the only guide that explains something about that: HTML5 ROCKS - FILESYSTEM.
I need to get storage for my extension and I resolved so:
window.webkitStorageInfo.requestQuota(window.PERSISTENT,1024*1024, onInitFs, errorHandler);
Ok, it works.
Now I need to create a xml file into the root, but in "onInitFs" the "fs" var is only a number and "fs.root" can't get it.
function onInitFs(fs){
console.log(fs.root); // -> Undefined
fs.root.getFile('list.xml', {create: true, exclusive: true}, function(fileEntry) {
fileEntry.isFile === true;
fileEntry.name == 'list.xml';
fileEntry.fullPath == '/list.xml';
}, errorHandler);
}
Can anybody explain why it doesn't work and how to resolve this issue?
Using RequestFileSystem within Chrome Extension
In order to use the FileSystem API as a root filesystem for your Chrome extension, you can actually use window.webkitRequestFileSystem instead of requestQuota.
window.webkitRequestFileSystem(window.PERSISTENT, 1024 * 1024, function (filesystem) {
console.log(filesystem);
console.log(filesystem.root);
}, function (e) { console.log("Could not request File System"); });
This does print correctly on Chrome 15,16 and 17 for me:
DOMFileSystem
DirectoryEntry
Using requestQuota for HTML5 apps
Just for reference, this would be the way to actually request the quota (i.e., when not using a Chrome Extension). You have to request the quota (the user sees a little banner at the top of his/her window) first. The RequestFileSystem is called if the user accepts.
window.webkitStorageInfo.requestQuota(PERSISTENT, 1024*1024, function(grantedBytes) {
window.webkitRequestFileSystem(PERSISTENT, grantedBytes, onInitFs, errorHandler);
}, function(e) {
console.log('Error requesting filesystem', e);
});
Eventually it might be necessary to request quota within an extension. Currently this can be circumvented with the unlimitedStorage permission. For the current state of implementation/storage types, see http://code.google.com/chrome/whitepapers/storage.html
Until current stable version 17.x, you cannot use HTML5 FileSystem API in Chrome extension. I have try this, the browser will crash down if I call FileSystem API in background page.
And here is a HTML5 API list what you can use in Chrome extension:
http://code.google.com/chrome/extensions/api_other.html

Logout through XMLHTTPRequest Object is not working in Opera

I am using the basic authentication mechanism for my website in IIS. To logout the user I am using something similar to this JavaScript function:
function logoutUser() {
setTimeout('location.reload(true)', 1000);
xmlhttp = GetXmlHttpObject();
if (xmlhttp==null) {
return;
}
//alert(xmlhttp);
var url = "index.php";
xmlhttp.open("GET", url, true, "dummy_user", "dummy_password");
xmlhttp.setRequestHeader( "If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT" );
xmlhttp.setRequestHeader( 'Accept', 'message/x-formresult' );
xmlhttp.send(null);
}
function GetXmlHttpObject()
{
if (window.XMLHttpRequest)
{
// code for IE7+, Firefox, Chrome, Opera, Safari
return new XMLHttpRequest();
}
if (window.ActiveXObject)
{
// code for IE6, IE5
return new ActiveXObject("Microsoft.XMLHTTP");
}
return null;
}
The idea is to force a request with some invalid credentials, in order to invalidate the real credentials cached by the browser.
It is working fine in IE,Firefox, Safari, Google Chrome but not in Opera.
Please help me in this regard.
That setting invalid credentials in an XMLHttpRequest should cause valid credentials to be discarded is not something you can rely on. It happens to work in many browsers but it's not at all standardised. Opera is not doing anything wrong by ignoring the credentials.
There is no standard way to cause HTTP Basic Authentication credentials to be dropped. There's one more way which works more widely, which is to have a link to /logout, a script that responds 401 when the user has valid credentials instead of when they do not. That will pop open an auth dialog, in which the user can fill in nonsense values or just empty strings; then when /logout is re-requested, it accepts those credentials, replacing the old ‘real’ ones.
Pairing this method and XMLHttpRequest is about the best you can do to provide logout capability for HTTP Authentication today.
Use any good JavaScript library. eg.jQuery...
so you will have not any browser specific problem.
It will be better to do an ajax call to a page that destroys session data; a page like logout.asp that has a call to Session.Abandon() or session_destroy() in php language
logout.php:
<?php session_destroy();?>
logout.aspx or logout.asp:
//other functions can go here before ending the session
<% Session.Abandon() %>
then the javascript function :
function(){
$.ajax({
url:'logout.php',//or logout.aspx or logout.asp
success:function(){location.reload();},
});
}
you should load jquery.js on the page that is making this logout call

Using jQuery.getJSON in Chrome Extension

I need to do a cross-domain request in a chrome extension. I know I can it via message passing but I'd rather stick to just jQuery idioms (so my javascript can also work as a <script src="">).
I do the normal:
$.getJSON("http://api.flickr.com/services/feeds/photos_public.gne?tags=cat&tagmode=any&format=json&jsoncallback=?", function(data) {
console.log(data);
});
but in the error console I see:
Uncaught ReferenceError: jsonp1271044791817 is not defined
Is jQuery not inserting the callback function correctly into the document? What can I do to make this work?
(If I paste the code into a chrome console, it works fine, but if I put it as the page.js in an extension is when the problem appears.)
Alas, none of these worked, so I ended up doing the communication via the background.html.
background.html
<script src="http://code.jquery.com/jquery-1.4.2.js"></script>
<script>
function onRequest(request, sender, callback) {
if (request.action == 'getJSON') {
$.getJSON(request.url, callback);
}
}
chrome.extension.onRequest.addListener(onRequest);
</script>
javascripts/page.js
chrome_getJSON = function(url, callback) {
console.log("sending RPC");
chrome.extension.sendRequest({action:'getJSON',url:url}, callback);
}
$(function(){
// use chrome_getJSON instead of $.getJSON
});
If you specify "api.flickr.com" in your manifest.json file you will not need to use the JSONP callback, script injection style of cross domain request.
For example:
"permissions": ["http://api.flickr.com"],
This should work beautifully in you code. I would remove the querystring parameter "&jsoncallback" as there is no JSONP work needed.
The reason why your current code is not working is your code is injecting into pages DOM, content scripts have access to the DOM but no access to javascript context, so there is no method to call on callback.
My impressions it that this fails because the jQuery callback function is being created within the 'isolated world' of the Chrome extension and is inaccessible when the response comes back:
http://code.google.com/chrome/extensions/content_scripts.html#execution-environment
I'm using Prototype and jQuery for various reasons, but my quick fix should be easy to parse:
// Add the callback function to the page
s = new Element('script').update("function boom(e){console.log(e);}");
$$('body')[0].insert(s);
// Tell jQuery which method to call in the response
function shrink_link(oldLink, callback){
jQuery.ajax({
type: "POST",
url: "http://api.awe.sm/url.json",
data: {
v: 3,
url: oldLink,
key: "5c8b1a212434c2153c2f2c2f2c765a36140add243bf6eae876345f8fd11045d9",
tool: "mKU7uN",
channel: "twitter"
},
dataType: "jsonp",
jsonpCallback: callback
});
}
// And make it so.
shrink_link('http://www.google.com', "boom");
Alternatively you can try using the extension XHR capability:
http://code.google.com/chrome/extensions/xhr.html
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://api.example.com/data.json", true);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
// JSON.parse does not evaluate the attacker's scripts.
var resp = JSON.parse(xhr.responseText);
}
}
xhr.send();
The syntax is a little off. There's no need for the callback( bit. This works flawlessly. Tested in the javascript console of Chrome on this StackOverflow page (which includes jQuery):
$.getJSON("http://api.flickr.com/services/feeds/photos_public.gne?tags=cat&tagmode=any&format=json&jsoncallback=?", function(data) {
console.log(data);
});
As many of you will know, Google Chrome doesn't support any of the handy GM_ functions at the moment.
As such, it is impossible to do cross site AJAX requests due to various sandbox restrictions (even using great tools like James Padolsey's Cross Domain Request Script)
I needed a way for users to know when my Greasemonkey script had been updated in Chrome (since Chrome doesn't do that either...). I came up with a solution which is documented here (and in use in my Lighthouse++ script) and worth a read for those of you wanting to version check your scripts:
http://blog.bandit.co.nz/post/1048347342/version-check-chrome-greasemonkey-script