I am new to nodejs, what I'm trying to do is to scan all the url of my site (with javascript and jquery enabled) and check that the url contains a given string.
To do this I'm using jsdom, but when I launch the script extracts only some url and then crashes giving this error:
timers.js:110
first._onTimeout();
^
TypeError: Property '_onTimeout' of object [object Object] is not a function
at Timer.listOnTimeout [as ontimeout] (timers.js:110:15)
Surely there is something wrong but I don't understand where..
This is my script:
var request = require('request');
var jsdom = require('jsdom');
request({ uri: 'http://www.example.com' }, function (error, response, html) {
if (!error && response.statusCode == 200) {
var doc = jsdom.jsdom(html, null, {
features: {
FetchExternalResources : ['script'],
ProcessExternalResources : ['script'],
MutationEvents : '2.0',
}
});
var window = doc.createWindow();
jsdom.jQueryify(window, "http://code.jquery.com/jquery-1.5.min.js", function() {
var $ = window.jQuery;
$('a').each(function(i, element){
var a = $(this).attr('href');
console.log(a);
if (a.indexOf('string') != -1) {
console.log('The winner: '+a);
//return a;
}
});
window.close();
});
}
});
This is because of somewhere in your page they are calling setTimeout/setInterval with a string that is not supported in node and it results in that error.
To find out where is it coming from, I suggest just require longjohn module(require('longjohn')) and you get long stack traces, which they will help you to find the error. For example I got something like this from doing this in the repl:
at listOnTimeout (timers.js:110:15)
---------------------------------------------
at startTimer (/home/alfred/repos/node_modules/jsdom/lib/jsdom/browser/index.js:75:15)
at DOMWindow.setTimeout (/home/alfred/repos/node_modules/jsdom/lib/jsdom/browser/index.js:124:50)
at file:///home/alfred/repos/repl:undefined:undefined<script>:1:1
at Contextify.sandbox.run (/home/alfred/repos/node_modules/jsdom/node_modules/contextify/lib/contextify.js:12:24)
at exports.javascript (/home/alfred/repos/node_modules/jsdom/lib/jsdom/level2/languages/javascript.js:5:14)
at define.proto._eval (/home/alfred/repos/node_modules/jsdom/lib/jsdom/level2/html.js:1523:47)
at /home/alfred/repos/node_modules/jsdom/lib/jsdom/level2/html.js:76:20
at item.check (/home/alfred/repos/node_modules/jsdom/lib/jsdom/level2/html.js:345:11)
If by any chance that didn't work for you or you didn't like it, then I suggest you to modify this jsdom file: node_modules/jsdom/lib/jsdom/browser/index.js, function startTimer. Throw an error there if the callback wasn't a function. This will throw whenever offending code was run.
In case if you are running code that you can't change(like from websites you don't own, which I don't suggest it because foreign javascript like that could be used to attack your app), you could override DOMWindow.setTimeout/.setInterval to support string arguments. You could also make open an issue for jsdom to have this opt-in.
Related
I have a C# function that is invoking a Javascript function, this is the C# function:
await _jsRuntime.InvokeVoidAsync("setMediaUsingStreaming", type, dotnetImageStream);
And this is the Javascript function:
async function setMediaUsingStreaming(fileType, fileStream) {
try {
const arrayBuffer = await fileStream.arrayBuffer();
const blob = new Blob([arrayBuffer]);
const url = URL.createObjectURL(blob);
var newHTMLElement;
var fileHTMLElement = document.getElementById('fileDisplay');
if (fileType == "image") {
newHTMLElement = document.createElement('img');
}
else {
newHTMLElement = document.createElement('video');
var attribute = document.createAttribute('controls');
newHTMLElement.setAttributeNode(attribute);
}
fileHTMLElement.appendChild(newHTMLElement);
newHTMLElement.src = url;
} catch (Exception)
{
console.log(Exception)
}
}
When the C# function is invoking the Javascript function I receive this error :
blazor.webassembly.js:1 Uncaught (in promise) Error:
Microsoft.JSInterop.JSException: Cannot set properties of null
(setting 'src') TypeError: Cannot set properties of null (setting
'src')
The weird thing is that I receive this error when I run the app in publish mode (withouth a debugger) but it works perfectly in debug mode. The catch from the javascript function is not hit when I receive this error, it seems that is the C# method that is throwing it.
I know what the error is saying, that the url variable is null, but I don't understand why is null, and why it works on debug mode.
Do you have any ideas ?
I have a PhantomJS script that works when I run it locally (Mac), but when I run it on my Linux server, it returns the following error:
ReferenceError: Can't find variable: $
https://fantasy.premierleague.com/a/statistics/value_form:5712 in global code
The code is:
var page = require('webpage').create();
var fs = require('fs');
var args = require('system').args;
page.settings.userAgent = 'SpecialAgent';
page.open('https://fantasy.premierleague.com/a/statistics/value_form', function (status) {
if (status !== 'success') {
console.log('Unable to access network');
} else {
var ua = page.evaluate(function () {
var result ="";
// ...
return result;
});
}
phantom.exit();
});
There may be a race condition between your code and jQuery being loaded on the page. Wrap the statements in your page.evaluate callback with a $(document).ready(function() { /* your statements here */ }); to ensure scripts on the page have loaded fully.
For anyone who is still using PhantomJS and encounters this problem, I solved it with
phantomjs --ignore-ssl-errors=yes
I don't intend for upvote.
I'm providing solution to solve some situations without simulating browser behavior with phantomjs just to retrieve data that can be handled directly by requesting to url.
You need the data from the page, so why not just do request to this url: https://fantasy.premierleague.com/drf/bootstrap-static
var request = require('request'); // install: npm i request
var fs = require('fs');
var args = require('system').args;
request.get({url: 'https://fantasy.premierleague.com/drf/bootstrap-static'}, function(err, response, body) {
console.log(body);
});
How I found this url?
Simple:
I have a node.js client which downloads and decrypts an AES encrypted file from another host.
var base64 = require('base64-stream');
var crypto = require('crypto');
var aes = crypto.createDecipher('aes-256-cbc', crypto.createHash('sha256').update(pass).digest('hex'));
// file stream
var file = fs.createWriteStream(params.target);
var base64reader = base64.decode();
response.pipe(base64reader) // decode base64
.pipe(aes) // decrypt
.pipe(file); // write in file
// on last data chunk received: file load complete
aes.on('end', function (chunk) {
if (typeof params.success !== 'undefined')
params.success();
});
If the other host close his connection unexpectedly before finishing the request, the code above throws this error:
TypeError: error:0606506D:digital envelope routines:EVP_DecryptFinal_ex:wrong final block length
at Decipher.Cipher._flush (crypto.js:262:27)
at Decipher.eval (_stream_transform.js:130:12)
at Decipher.g (events.js:187:16)
at Decipher.EventEmitter.emit (events.js:95:17)
at prefinish (_stream_writable.js:427:12)
at finishMaybe (_stream_writable.js:435:7)
at afterWrite (_stream_writable.js:317:3)
at onwrite (_stream_writable.js:307:7)
at WritableState.onwrite (_stream_writable.js:100:5)
at afterTransform (_stream_transform.js:99:5)
at TransformState.afterTransform (_stream_transform.js:74:12)
at Decipher.Cipher._transform (crypto.js:258:3)
at Decipher.Transform._read (_stream_transform.js:179:10)
at Decipher.Readable.read (_stream_readable.js:334:10)
at flow (_stream_readable.js:743:26)
at WriteStream.eval (_stream_readable.js:601:7)
I tried to add an aes.on('error', function(() {...}); handler but it will not be called. I also tried adding
response.on('end', function() { aes.emit('close'); });
response.on('close', function() { aes.emit('close'); });
but then aes.on('end', ...); will not be called. Adding aes.emit('end') to this statements make no sense, because this will be also called in case of an error which leads to the error above.
response.on('end', function() { aes.emit('end'); aes.emit('close'); });
response.on('close', function() { aes.emit('end'); aes.emit('close'); });
Does anybody have an idea how I can catch this error?
Thanks a lot!!
Its a bug in node.js v0.11.9 which is solved in v0.11.13. Then aes.on('error', ...) will be called correctly.
So I'am using a api wrapper package which again uses request for the api requests. Which works fine in most setups. But I want to use that package in a node-webkit environment and use a XHR in place of the request module. It would work with the API and works if I rewrite the module. But I don't wanna do that because of the update comfort. So forking is not an option for me. Is it possible to replace one function in a module without replacing the module.
var request = require('request');
var makeRequest = function(path, args, secure, callback, encoding) {
var maxlen = 2048;
var path = buildUrl(path, args);
if (path.length > maxlen) {
throw new Error("Request too long for google to handle (2048 characters).");
}
var options = {
uri: (secure ? 'https' : 'http') + '://some.api.com' + path
};
if (encoding) options.encoding = encoding;
if (config('proxy')) options.proxy = config('proxy');
if (typeof callback === 'function') {
request(options, function (error, res, data) {
if (error) {
return callback(error);
}
if (res.statusCode === 200) {
return callback(null, data);
}
return callback(new Error("Response status code: " + res.statusCode), data);
});
}
return options.uri;
};
module.exports = makeRequest;
So now i want to replace the request function oder the whole makeRequest function without changing the makeRequest. So basicly I want to overwrite the function.
edit: Add code Example.
take a look at rewire or proxyquire, that could solve your problems.
i dont see any other solution if the module you use uses makeRequest only internally, and even then this only works if makeRequest is required within the module (file) you require.
but keep in mind, this is probably bad, and should usually only be used for testing.
I have this javascript code which makes possible writing in a file
{
var fileSystemObj = new FileSystem();
var fileObj = fileSystemObj.openCommonFile(curWidget.id +
‘/testFile.data’, ‘w’);
fileObj.writeLine(‘something to write.’);
fileSystemObj.closeCommonFile(fileObj);
}
but it doesn't work. Doesn't even display any error!
samsung developer forum (you may not see unless you sign in... )
I am quoting it.
case tvKey.KEY_RED:
alert('RED BUTTON!');
alert('CWID: '+curWidget.id);
try {
var fileSystemObj = new FileSystem();
var fileObj = fileSystemObj.openCommonFile(curWidget.id+'/testFile.data','w');
fileObj.writeLine('something to write.');
fileSystemObj.closeCommonFile(fileObj);
} catch (e) {
alert('Error: file handling: '+e);
}
break;
lead to error:
alert() : Error: file handling: TypeError: 'null' is not an object
(evaluating 'fileObj.writeLine')
Reading cause same problem.
and solution accepted in that link is:
I suppose that problem is that you have to create common dir (if does not exist ) at first :
var fileObj = fileSystemObj.openCommonFile(filePath, 'w');
if(!fileObj){
var bValid = fileSystemObj.isValidCommonPath(curWidget.id);
if (!bValid) {
fileSystemObj.createCommonDir(curWidget.id);
}
}
fileObj = fileSystemObj.openCommonFile(filePath, 'w');
fileObj.writeLine('something to write.');
fileSystemObj.closeCommonFile(fileObj);