In the extension I am building, on click of a button, a request is sent from ChromeUtils.js
return new Promise(function(fulfill,reject){
var request = {
type : "background.twitterRequestToken",
};
chrome.runtime.sendMessage(request, function(response) {
if (response)
{
fulfill(response);
}
else
{
reject(response);
}
});
});
to the background.js which in turn calls an oauth Api to send a request to the remote server.
chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
console.log("background.js: " + JSON.stringify(request));
var type = request.type;
if (type == "background.twitterRequestToken")
{
oauth.authorize().then(function(token,secret,userId,screenname){
console.log("Sending Response on Authorize");
sendResponse({success:true,userId:userId,screenName:screenname});
});
console.log("Before Return true");
return true;
}
I am using the oauth scripts from the example given at https://developer.chrome.com/extensions/tut_oauth but due to a requirement have modified the oauth to use promise. When implemented as a promise, the sendResponse fails but when using the default implementation using callbacks. the sendResponse goes through.
Default implementation using callbacks:
if (type == "background.twitterRequestToken")
{
oauth.authorize(function(token,secret,userId,screenname){
console.log("Sending Response on Authorize");
sendResponse({success:true,userId:userId,screenName:screenname});
});
console.log("Before Return true");
return true;
}
Error message in the background console when implemented as a promise is
Uncaught (in promise) Error: Attempting to use a disconnected port object
The reason I want to use a promise is that when sending signedRequests using Oauth, I want to include part of the xhr response in the sendResponse, e.g. as shown below.
if (type == "background.tweet")
{
var status = request.tweet.text;
var url = "https://api.twitter.com/1.1/statuses/update.json";
var request = {
'method':'POST',
'parameters': {
'status':status
}
}
oauth.sendSignedRequest(url,request).then(signedRequestCallback).then(function(resp,xhr){
console.log("signedRequestCallback success");
console.log("Sending response");
sendResponse({success:true,status_id:resp.id});
});
return true;
}
I have already included return true in my code and as I explained it works fine when not using Promise. It fails when using Promise because the of the error message I included.
===============Update========
To repro this I created a simpler example but I do not face the issue there when I use a Promise. So this may not have anything to do with Promise.
Related
Problem: when developing an Ionic2 app, I would like to see the console.log messages generated on my IPhone but I do not have a Mac or I do have one but found that the web inspector feature sucks.
Note this is applicable to any kind of remote javascript, not only to Angular/ionic.
This is a Q&A style question, meaning I'll provide the answer below because I think it's very useful for lots of people.
The solution is a hook into your javascript that will intercept all console.log and errors and send them to a server.
Place the following code into your index.html page:
<script>
// Function that will call your webserver
logToServer = function(consoleMsg) {
// only do this if on device
if (window.cordova) {
let jsonTxt = customStringify(consoleMsg);
var xmlHttp = new XMLHttpRequest();
xmlHttp.open("GET", 'http://yourserver/console2server.php?msg=' + jsonTxt, true); //async
xmlHttp.send(null);
}
}
// Test if you receive this on the server
logToServer("OPENING IONIC APP");
// intercept console logs
(function () {
var oldLog = console.log;
console.log = function (message) {
// DO MESSAGE HERE.
logToServer(message);
oldLog.apply(console, arguments);
};
})();
// intecept errors
if (window && !window.onerror) {
window.onerror = function (errorMsg, url, lineNumber, column, errorObj) {
logToServer(errorMsg);
logToServer(errorObj);
return false;
}
}
// this is optional, but it avoids 'converting circular structure' errors
customStringify = function (inp) {
return JSON.stringify(inp, function (key, value) {
if (typeof value === 'object' && value !== null) {
if (cache.indexOf(value) !== -1) {
// Circular reference found, discard key
console.log("circular dep found!!");
return;
}
// Store value in our collection
cache.push(value);
}
return value;
});
}
</script>
On the server side, I use PHP but you could use whatever you want:
<?php
//allow CORS request
header('Access-Control-Allow-Origin: *');
if(isset($_GET['msg'])) {
//you can also log to a file or whatever, I just log to standard logs
error_log("[CONSOLE.LOG] ".json_decode($_GET['msg'], true));
}
?>
Happy debugging!
I am trying to intercept web request to a particular url and before sending the request, contact a native app through web extension native messaging (which is async). Since the native messaging is async, the web request gets sent before the cookie value is got from native messaging response.
Here is the code snippet. How to make this flow synchronous so that the cookie is loaded and then the intercepted web request is sent.
browser.webRequest.onBeforeRequest.addListener(
loadCookie,
{urls: ["https://some-url/*"]},
["blocking"]
);
function loadCookie(requestDetails)
{
console.log("Gettting Cookie Data for"+requestDetails.url);
var sending = browser.runtime.sendNativeMessage("native_app","getCookieData");
sending.then(onSuccess, onError);
}
function onSuccess(response)
{
console.log("Received: " + JSON.stringify(response));
setCookie(response);
}
function onError(error)
{
console.log("Error");
}
function setCookie(resp)
{
if(typeof resp != 'undefined'){
var now = new Date();
var time = Math.round(now.getTime() / 1000);
var expireTime = time + 15*60;
browser.cookies.set({
url: "https://some-domain/*",
name: "req_cookie",
value: resp,
secure: true,
expirationDate: expireTime
});
}
console.log("Set a cookie");
}
In order to set the cookie header, I think you will need to listen to onBeforeSendHeaders, not onBeforeRequest.
The documentation for onBeforeSendHeaders (and onBeforeRequest) says :
From Firefox 52 onwards, instead of returning a BlockingResponse, the listener can return a Promise which is resolved with a BlockingResponse. This enables the listener to process the request asynchronously.
I am currently trying to learn how to do HTTP requests in Meteor. When I run the code, I can properly see the data in the console. However, on the client side all I get is "undefined". I believe I'm running the HTTP.get method synchronously.
.JS file
if (Meteor.isClient) {
Template.test.helpers({
testGET: function(){
var origin = Meteor.call('fetchFromService');
console.log(origin); //-- Displays 'Undefined'
}
});
}
if (Meteor.isServer) {
Meteor.methods({
fetchFromService: function() {
this.unblock();
var url = "https://httpbin.org/get";
var result;
try{
result = HTTP.get( url );
} catch(e) {
result = "false";
}
console.log(result.data.origin); //-- Displays the data properly
return result.data.origin;
}
});
}
It's async, you have to pass a callback to the call function:
var origin = Meteor.call('fetchFromService', function(err, data) {
console.log(data);
});
If you don't pass the callback, origin will be undefined until the request finishes.
I would like my AngularJS app to capture "no internet connection" just like how Chrome captures it. When Chrome captures it, it shows net::ERR_INTERNET_DISCONNECTED on the console.log.
Angular's HTTP interceptor is not able to capture it. The only data I get is
rejection.data.status undefined
rejection.status 0
So far, this has been working great. I noticed that the status is 0 when it can't contact anything. This is inside my http interceptor
responseError: function (rejection) {
if (rejection.status == 0) {
// put whatever behavior you would like to happen
}
// .......
return $q.reject(rejection);
}
A simple script that could help you, you could do it in different ways, even loading an image and call a function when this fails.
function getNetworkStatus(callback, timeout, x){
x = new XMLHttpRequest();
x.timeout = timeout,
x.onreadystatechange = function(){
x.readyState == 4 && callback(x.status == 200)
}, x.onerror = function(e){
callback(!1)
}, x.ontimeout = function(){
callback(!1)
}, (x.open("GET", "http://ip-api.com/json/"), x.send());
}
getNetworkStatus(function(isOnline){
console.info(isOnline ? "ONLINE" : "OFFLINE");
},60000);
UPDATE
We define this interceptor in httpProvider, so return strictly an error when a call does not happen successfully
angular.module('MyApp', []).config([
'$httpProvider',
function($httpProvider) {
$httpProvider.interceptors.push([
'$q',
function($q) {
return {
responseError: function(res){
console.info("Failed to open url: " + res.config.url, res);
//Angular returns "success" by default, but we will call "error" if data were not obtained.
if(res.data == null && res.status === 0 && res.statusText === ""){
return $q.reject(res) //callback error()
}
return res //return default success()
}
};
}
]);
}
]).run(['$http', function($http) { // --TEST--
//$http.get("http://ip-api.com/json/").success(function(){ //page online
$http.get("https://ip-api.com/json/").success(function(){ //try "https" (page offline to test)
console.info("My great page is loaded - We are online :)",arguments)
}).error(function(){
console.info("ERROR: My great online page is not loaded :/ - possibility of connection loss?",arguments)
});
}]);
You can change a trusted URL that you think will never be offline, for example Google, but remember, the url should have origin access permissions that does not show the "Access-Control-Allow-Origin" error. http://ip-api.com/json/ is ok.
I'm developing an jQuery application in where I've a requirement to capture HTTP errors as and when it occurs. Below is my snippet.
// Function to validate URL
function validateURL(url)
{
var pattern = new RegExp();
pattern.compile("^[A-Za-z]+://[A-Za-z0-9-_]+\\.[A-Za-z0-9-_%&\?\/.=]+$");
if (!pattern.test(url))
{
return false;
}
return true;
}
// Generic error handler for handling the webservice requests.
function initWebService(wstype, wsurl,jsonData)
{
// If the method parameter is not either "GET" or "POST" display an error message to the developer.
var msgValidateArgument;
var wsCallStatus;
var callbackData;
if ((arguments[0] != 'GET') && (arguments[0] != 'POST'))
{
//alert("Invalid");
//alert("You must provide a valid http method in your webservice call.");
msgValidateArgument = "You must provide a valid http method in your webservice call.";
return msgValidateArgument;
}
// Making sure whether the developer is passing the required number of parameters.
if(arguments.length < 3)
{
//alert("Some required arguments seems to be missing. Please check your webservice invocation.");
msgValidateArgument = "Some required arguments seems to be missing. Please check your webservice invocation.";
return msgValidateArgument;
}
if (!validateURL(arguments[1]))
{
msgValidateArgument = "You must provide a valid URL in your webservice call.";
return msgValidateArgument;
}
if(arguments[2] != ''){
var response=jQuery.parseJSON(arguments[2]);
if(typeof response =='object'){
//It is JSON
alert(response.toSource());
}
else{
msgValidateArgument = "The JSON data being passed is not in valid JSON format.";
return msgValidateArgument;
}
}
// Making the AJAX call with the parameters being passed. The error handler handles some of the possble http error codes as of now.
$.ajax({
type: arguments[0],
url: arguments[1],
data: arguments[2],
dataType: 'json',
async:false,
statusCode:{
404: function(){
alert('Page not found');
},
500: function(){
alert('Page not found');
},
504: function(){
alert('Unknown host');
}
},
success: function(data){
//alert('Data being returned from server: ' +data.toSource());
//alert('Data being returned from server: ' +data.toSource());
//alert(data);
callbackData = data;
}
});
return callbackData;
}
But, when I programatically change the webservice url to hold a wrong value, and upon calling the html page, I'm able to see an error message in the firebug console, but my snippet doesn't seem to be catching the error at all.
For e.g, While calling the GEONames API, I'm encountering an stating "407 Authorization required" in firebug's console.but even if I handle that status code in my error block, it is not firing.. What could be the reason?.
Don't we have any comprehensive solution for handling these HTTP errors effectively?.
I think there are a few problems with your code ... firstly how is handleError called ? because you call a method called handleError but pass nothing ... im assuming your using .ajax()
You should do it like this :
$.ajax({
statusCode: {
404: function() {
alert('page not found');
},
500: function() {
alert('server error');
}
},
success : {
alert('it working');
},
complete : {
alert('im complete');
});