How to get images from cache using a XPCOM Component in Firefox - firefox-addon

I need to get the cache file path for ever image loaded in a document, I am wondering what are the Interfaces I need to use in order to do that
https://developer.mozilla.org/en/XPCOM_Interface_Reference

This is what I used to evict cache entry:
function removeItem(url){
let cacheService = Components.classes["#mozilla.org/network/cache-service;1"]
.getService(Components.interfaces.nsICacheService);
var Ci = Components.interfaces;
var session = cacheService.createSession("image", Ci.nsICache.STORE_ANYWHERE, false);
if(!session){
return;
}
var entry;
try{
entry = session.openCacheEntry(url, Ci.nsICache.ACCESS_READ, false);
if(!entry){
return;
}
}catch(ex){
return;
}
entry.doom();
entry.close();
}
}
Once you have entry you should be able to open a stream to it - possibly getting the content or even replacing it - I haven't tried it though.

Related

PDFJS.getDocument not working and not throwing an error

It's not going into the .then afterwards, and it's not throwing any error.
Here's my calling code:
function loadPage(base64Data, pageIndex) {
var pdfData = base64ToUint8Array(base64Data);
// this gets hit
PDFJS.getDocument(pdfData).then(function (pdf) {
// never gets here
pdf.getPage(pageIndex).then(function (page) {
var scale = 1;
var viewport = page.getViewport(scale);
var canvas = document.getElementById('pdfPage');
var context = canvas.getContext('2d');
canvas.height = viewport.height;
canvas.width = viewport.width;
page.render({ canvasContext: context, viewport: viewport });
});
});
}
function base64ToUint8Array(base64) {
var raw = atob(base64); // convert base 64 string to raw string
var uint8Array = new Uint8Array(raw.length);
for (var i = 0; i < raw.length; i++) {
uint8Array[i] = raw.charCodeAt(i);
}
return uint8Array;
}
At one point it worked. When I step through it in the debugger, I can step into PDFJS.getDocument but that's way over my head.
My base64Data looks like JVBERi0x...g==. It's a base64 encoded pdf document.
To solve this, I had to add
PDFJS.disableWorker = true;
to the beginning of my loadPage function.
From View PDF files directly within browser using PDF.js,
PDF.js uses Web Workers concept of HTML5 internally to process the
request. If this statement is set to false, it creates an instance of
Web workers. Web Workers run in an isolated thread. For more
information on web workers; please refer
http://www.html5rocks.com/en/tutorials/workers/basics/
Promise is missing in your code. Here how i fixed this probelm:
PDFJS.getDocument(pdfData).promise.then(function (pdf) {
// do your stuff
});

Firefox addon - monitoring network

If I add an nsIHttpChannel observer, is there any way I can know what initiated the HTTP request(script, iframe, image etc..)
In chrome when monitoring the network from the background page you have the request type telling you if it came from an iframe, script etc...
Don't accept this as solution yet. I hope some other people can come and help build this solution.
I know this is for sure correct:
TEST FOR: XHR - identify XHR (ajax) response while listening to http response in firefox addon
Get load context of request (like which tab, which html window, which xul window) - Firefox add-on pageMod, catch ajax done in contentScriptFile (this is marked as optional though in the code below it requires a helper function: https://gist.github.com/Noitidart/644494bdc26f996739ef )
This I think is correct, by this i mean it works in my test cases but I'm not sure if its the recommended way:
TEST FOR: Frame or full page load - Can we differentiate between frame and non-frame loads with Ci in firefox addon
This I don't know how to do so I need help from community on this:
TEST FOR image - Comment on "identify XHR (ajax) response while listening to http response in firefox addon"
Image detection can be done through the MIME type. Check channel.contentType
Solution in progress:
var myobserve = function(aSubject, aTopic, aData) {
var httpChannel = aSubject.QueryInterface(Ci.nsIHttpChannel);
//start - test if xhr
var isXHR;
try {
var callbacks = httpChannel.notificationCallbacks;
var xhr = callbacks ? callbacks.getInterface(Ci.nsIXMLHttpRequest) : null;
isXHR = !!xhr;
} catch (e) {
isXHR = false;
}
//end - test if xhr
//start - test if frame OR full page load
var isFrameLoad;
var isFullPageLoad;
if (httpChannel.loadFlags & Ci.nsIHttpChannel.LOAD_INITIAL_DOCUMENT_URI) {
isFullPageLoad = true;
isFrameLoad = false;
} else if (httpChannel.loadFlags & Ci.nsIHttpChannel.LOAD_DOCUMENT_URI) {
isFrameLoad = true;
isFullPageLoad = false;
}
//end - test if frame OR full page load
//start - test if image
var isImg;
var isCss;
var isJs;
var isAudio;
//can keep going here
var mimeType = httpChannel.contentType;
if (/^image/i.test(mimeType)) {
isImg = true;
}
if (/^audio/i.test(mimeType)) {
isAudio = true;
}
if (/\/css$/i.test(mimeType)) {
isCss = true;
}
if (/\/js$/i.test(mimeType)) {
isJs = true;
}
//end - test if image
//start - OPTIONAL use loadContext to get a bunch of good stuff
//must paste the function from here: https://gist.github.com/Noitidart/644494bdc26f996739ef somewhere in your code
var goodies = loadContextAndGoodies(aSubject, true);
/*
//goodies is an object that holds the following information:
var goodies = {
loadContext: loadContext,
DOMWindow: DOMWindow,
gBrowser: gBrowser,
contentWindow: contentWindow,
browser: browser,
tab: tab
};
*/
// test if resource (such as image, or whatever) is being loaded is going into a frame [can also be used as altnerative way to test if frame load or full page]
var itemDestinationIsFrame;
var itemDestinationIsTopWin;
if (goodies.contentWindow) {
if (goodies.contentWindow.frameElement) {
itemDestinationIsFrame = true;
itemDestinationIsTopWin = false;
} else {
itemDestinationIsFrame = false;
itemDestinationIsTopWin = true;
}
}
//end - OPTIONAL use loadContext to get a bunch of good stuff
}
Of course to start observing:
Services.obs.addObserver(myobserve, 'http-on-modify-request', false);
and to stop:
Services.obs.removeObserver(myobserve, 'http-on-modify-request', false);
To start observing
To start start obseving all requests do this (for example on startup of your addon)
for (var o in observers) {
observers[o].reg();
}
To stop observing
Its important to stop observring (make sure to run this at least on shutdown of addon, you dont want to leave the observer registered for memory reasons)
for (var o in observers) {
observers[o].unreg();
}

Cordova Phonegap inappbrowser losing File Api functionality

I am developing an app using Web Audio Api. I have discovered that there is a memory leak in the way that Safari handles audio and doesn't garbage college the Audio Context correctly. For this reason I wish to load a new page. Have that page create the Audio Context, complete the operation and then close the window, so that the memory is released.
I have done the following to achieve this.
ref = window.open('record.html', '_self'); This will open the record.html page in the Cordova WebView according to https://wiki.apache.org/cordova/InAppBrowser
1 window.open('local-url.html');// loads in the
Cordova WebView
2 window.open('local-url.html', '_self');
// loads in the Cordova WebView
The record.html page loads a javascript file, that runs the operations that I wish to run. Here is the recordLoad.js file that makes some calls to native operations ( The native API is only available if loaded in the Cordova Webview and as you can see I need to access the file system, so this is the only way I can see to do it.
window.onload = createAudioContext;
ref = null;
function createAudioContext(){
console.log('createAudioContext');
window.AudioContext = window.AudioContext || window.webkitAudioContext;
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia;
window.URL = window.URL || window.webkitURL;
audioContext = new AudioContext;
getDirectory();
}
function getDirectory(){
console.log('getDirectory');
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, getFileSystem, fail);
}
function getFileSystem(directory){
console.log('getFileSystem');
var audioPath = localStorage.getItem('audioPath');
directory.root.getFile(audioPath, null, getVocalFile, fail);
}
function getVocalFile(fileEntry){
console.log('getVocalFile');
fileEntry.file(readVocalsToBuffer, fail);
}
function readVocalsToBuffer(file){
console.log('readVocalsToBuffer');
var reader = new FileReader();
reader.onloadend = function(evt){
var x = audioContext.decodeAudioData(evt.target._result, function(buffer){
if(!buffer){
console.log('error decoding file to Audio Buffer');
return;
}
window.voiceBuffer = buffer;
buffer = null;
loadBuffers();
});
}
reader.readAsArrayBuffer(file);
}
//web
function loadBuffers(){
console.log('loadBuffers');
var srcSong = localStorage.getItem('srcSong');
try{
var bufferLoader = new BufferLoader(
audioContext,
[
"."+srcSong
],
createOffLineContext
);
bufferLoader.load()
}
catch(e){
console.log(e.message);
}
}
//
function createOffLineContext(bufferList){
console.log('createOfflineContext');
offline = new webkitOfflineAudioContext(2, window.voiceBuffer.length, 44100);
var vocalSource = offline.createBufferSource();
vocalSource.buffer = window.voiceBuffer;
vocalSource.connect(offline.destination);
var backing = offline.createBufferSource();
backing.buffer = bufferList[0];
backing.connect(offline.destination);
vocalSource.start(0);
backing.start(0);
offline.oncomplete = function(ev){
bufferList = null;
console.log('audioContext');
console.log(audioContext);
audioContext = null;
console.log(audioContext);
vocalSource.stop(0);
backing.stop(0);
vocalSource.disconnect(0);
backing.disconnect(0);
vocalSource = null;
backing = null;
window.voiceBuffer = null;
window.renderedFile = ev.renderedBuffer;
var bufferR = ev.renderedBuffer.getChannelData(0);
var bufferL = ev.renderedBuffer.getChannelData(1);
var interleaved = interleave(bufferL, bufferR);
var dataview = encodeWAV(interleaved);
window.audioBlob = new Blob([dataview], {type: 'Wav'});
saveFile();
}
offline.startRendering();
}
// This file is very long, but once it is finished mixing the two audio buffers it writes a new file to the file system. And when that operation is complete I use
function gotFileWriter(writer){
console.log('gotFileWriter');
writer.onwriteend = function(evt){
console.log('onwriteEnd');
console.log(window.audioBlob);
delete window.audioBlob;
console.log(window.audioBlob);
// checkDirectory();
var ref = window.open('index.html', '_self');
// ref.addEventListener('exit', windowClose);
}
writer.write(audioBlob);
}
I return back to the original index.html file. This solves the memory issues. However, once I try to run the same operation a second time. ie load in the record.html file, and run the recordLoad.js file I receive an error ReferenceError: Can't find variable: LocalFileSystem
It would appear that in reload index.html some, but not all of the links to the Cordova API have been lost. I can still for example use the Media Api but not the File Api. I understand that this is a bit of a hacky way, (opening and closing windows) to solve the memory leak, but I cannot find any other way of doing it. I really need some help with this. So any pointers very very welcome.

Save current page from firefox add-on

I'm need a way to save the current page (including, images, CSS, etc.) from an add-on.
Of course I found the saveDocument() function in the SDK but I was not able to make it work.
from add-on script, I do not have access to actual DOM content
from content script, I do not have access to SDK function 'saveDocument()'
I miss something, I would be very happy if someone could help me.
Best regards,
Fred
here's one way to access the DOM document from addon script.
var winutil = require('sdk/window/utils');
function findDocument(predicate){
// searching in focused window only
// you can also get all windows with winutil.windows('navigator:browser')
var win = winutil.getMostRecentBrowserWindow();
var gBrowser = win.gBrowser;
// traverse tabs of focused window
for (var i=0, l=gBrowser.browsers.length; i<l; i++)
{
var br = gBrowser.getBrowserAtIndex(i);
var doc = br.contentDocument;
if (predicate(doc))
return doc;
}
}
// and this is probably how you would save (not tested)
var {Cc, Ci} = require('chrome');
var wbp = Cc["#mozilla.org/embedding/browser/nsWebBrowserPersist;1"]
.createInstance(Ci.nsIWebBrowserPersist);
var doc = findDocument(/* whatever */);
if (doc)
wbp.saveDocument(doc, /* figure out other args */);

how to create .txt in local file system using Firefox extension

I am currently working on ffsniff extension code. In that I have to save data containing password information into a file in my local system. I have written my code but it is not even creating the file in my local system. (working in mozilla firefox)
Here is my code please help me out.
//// here data variable contains all the information
var fso = new ActiveXObject("Scripting.FileSystemObject");
varFileObject = fso.OpenTextFile("C:\\logs.txt", 2, true,0);
varFileObject.write(data);
varFileObject.close();
after this i tried different code:
Components.utils.import("resource://gre/modules/NetUtil.jsm");
Components.utils.import("resource://gre/modules/FileUtils.jsm");
var file = Components.classes["#mozilla.org/file/directory_service;1"].
getService(Components.interfaces.nsIProperties).
get("Desk", Components.interfaces.nsIFile);
file.append("logs.txt");
var ostream = FileUtils.openSafeFileOutputStream(file)
var converter = Components.classes["#mozilla.org/intl/scriptableunicodeconverter"].
createInstance(Components.interfaces.nsIScriptableUnicodeConverter);
converter.charset = "UTF-8";
var istream = converter.convertToInputStream(data);
}
});
but none of them is working..
Here's a working snippet that creates the destination directory if necessary and writes (overwrites) to file (in this case d:\temp-directory\temp-file.txt):
var {Cc,Ci,Cu}=require("chrome"); //for jetpack sdk.
Cu.import("resource://gre/modules/NetUtil.jsm");
Cu.import("resource://gre/modules/FileUtils.jsm");
var localFile = Cc["#mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
var data="test file content";
//localFile.initWithPath("D:\\temp-directory\\temp-file.txt"); //full path is okay if directory exists
localFile.initWithPath("D:\\temp-directory\\"); //otherwise specifiy directory, create it if necessary, and append leaf.
if(!localFile.exists()){
localFile.create(localFile.DIRECTORY_TYPE,FileUtils.PERMS_DIRECTORY);
}
localFile.append("temp-file.txt");
//localFile.createUnique(localFile.NORMAL_FILE_TYPE,FileUtils.PERMS_FILE); //optional: create a new unique file.
asyncSave(localFile,data,onDone);
function asyncSave(file,data,callbackDone){
// file is nsIFile, data is a string, optional: callbackDone(path,leafName,statusCode)
// default flags: FileUtils.openSafeFileOutputStream(file, FileUtils.MODE_WRONLY | FileUtils.MODE_CREATE | FileUtils.MODE_TRUNCATE);
var ostream = FileUtils.openSafeFileOutputStream(file);
var converter = Cc["#mozilla.org/intl/scriptableunicodeconverter"].createInstance(Ci.nsIScriptableUnicodeConverter);
converter.charset = "UTF-8";
var istream = converter.convertToInputStream(data);
// optional: callbackSaved(status).
NetUtil.asyncCopy(istream, ostream, callbackSaved);
function callbackSaved (status) {
if(callbackDone){
if(status===0)callbackDone( file.path, file.leafName, status); //sucess.
else callbackDone( null, null, status); //failure.
};
}
}
function onDone(path,leafName,statusCode){
console.log([statusCode===0?"OK":"error",path,leafName].join("\n"));
}
More information:
https://developer.mozilla.org/en-US/docs/Code_snippets/File_I_O
https://developer.mozilla.org/en-US/docs/Mozilla/JavaScript_code_modules/FileUtils.jsm
https://developer.mozilla.org/en-US/docs/PR_Open
https://developer.mozilla.org/en-US/docs/Mozilla/JavaScript_code_modules/NetUtil.jsm
https://developer.mozilla.org/en-US/docs/XPCOM_Interface_Reference/nsIFile
https://developer.mozilla.org/en-US/docs/XPCOM_Interface_Reference/nsILocalFile
A simple example of how to read/write a file from the filesystem in windows, using Firefox Extension:
// Write File to filesystem
Components.utils.import("resource://gre/modules/osfile.jsm"); // load the OS module
var encoder = new TextEncoder(); // This encoder can be reused for several writes
var array = encoder.encode("just some text"); // Convert the text to an array
var promise = OS.File.writeAtomic("C:\\foo.txt", array,{tmpPath: "foo.txt.tmp"}); // Write the array atomically to "file.txt", using as temporary
alert("URL HOST has been saved");
//Read File from filesystem
var decoder = new TextDecoder(); // This decoder can be reused for several reads
var promise = OS.File.read("C:\\foo.txt"); // Read the complete file as an array
promise = promise.then(
function onSuccess(array) {
alert(decoder.decode(array)); // Convert this array to a text
}
);
This solution is for making file in ubuntu, hope this helps others:
var file = Components.classes["#mozilla.org/file/directory_service;1"].
getService(Components.interfaces.nsIProperties).
get("ProfD", Components.interfaces.nsIFile);
file.append("trick_new");
if( !file.exists() || !file.isDirectory() ) { // if it doesn't exist, create
file.create(Components.interfaces.nsIFile.DIRECTORY_TYPE, 0777);
}
this.log_file = file.path + "/newlog.html";
You can also use text-stream to write to a local file.
function writeTextToFile(text, filename) {
var fileIO = require("sdk/io/file");
var TextWriter = fileIO.open(filename, "w");
if (!TextWriter.closed) {
TextWriter.write(text);
TextWriter.close();
}
}

Resources