3

I'm developing a Firefox extension and I need to change the user agent of a single tab. I have used extensions such as User Agent Switcher, but it only let me change the user agent in the entire browser. Do you know if that is possible? Where can I read about?

Thanks a lot, G.

gal007
  • 6,911
  • 8
  • 47
  • 70

1 Answers1

3

this is a fun addon. i wanted to make an addon which enabled proxy only in single tab, i think this here helping u will lead me to make that sometime soon

copy paste code. it will spoof user-agent in all things loaded in tab 1. in all other tabs it will let the load go through. however if there is no loadContext you wont be able to tell which tab its coming from, so probably just ignore it and let it go.

we need advice from ppl more experienced then me. in what cases do we get a null loadContext?

on to the copy paste code

const {classes: Cc, Constructor: CC, interfaces: Ci, utils: Cu, results: Cr, manager: Cm} = Components;
Cu.import('resource://gre/modules/Services.jsm');

var myTabToSpoofIn = Services.wm.getMostRecentBrowser('navigator:browser').gBrowser.tabContainer[0]; //will spoof in the first tab of your browser

var httpRequestObserver = {
    observe: function (subject, topic, data) {
        var httpChannel, requestURL;

        if (topic == "http-on-modify-request") {
            httpChannel = subject.QueryInterface(Ci.nsIHttpChannel);
            var goodies = loadContextGoodies(httpChannel)
            if (goodies) {
              if (goodies.aTab == myTabToSpoofIn) {
                httpChannel.setRequestHeader('User-Agent', 'user agent spoofeddddd', false);
              } else {
                //we arent spoofing in this tab so ignore it
              }
            } else {
                //no goodies so we dont know what tab its from, im not sure when we dont have a loadContext we need to ask other ppl
                //no goodies for this channel, so dont know what tab its in so probably just load this, your decision though, make it option to user, if cannot find associated load context ask user if they want the data to be loaded with default user agent or just not load it at all
                //httpChannel.cancel(Cr.NS_BINDING_ABORTED); //uncomment this to abort it
            }
        }
    }
};

Services.obs.addObserver(httpRequestObserver, "http-on-modify-request", false);
//Services.obs.removeObserver(httpRequestObserver, "http-on-modify-request", false); //run this on shudown of your addon otherwise the observer stags registerd







//this function gets the contentWindow and other good stuff from loadContext of httpChannel
function loadContextGoodies(httpChannel) {
    //httpChannel must be the subject of http-on-modify-request QI'ed to nsiHTTPChannel as is done on line 8 "httpChannel = subject.QueryInterface(Ci.nsIHttpChannel);"
    //start loadContext stuff
    var loadContext;
    try {
        var interfaceRequestor = httpChannel.notificationCallbacks.QueryInterface(Ci.nsIInterfaceRequestor);
        //var DOMWindow = interfaceRequestor.getInterface(Components.interfaces.nsIDOMWindow); //not to be done anymore because: https://developer.mozilla.org/en-US/docs/Updating_extensions_for_Firefox_3.5#Getting_a_load_context_from_a_request //instead do the loadContext stuff below
        try {
            loadContext = interfaceRequestor.getInterface(Ci.nsILoadContext);
        } catch (ex) {
            try {
                loadContext = subject.loadGroup.notificationCallbacks.getInterface(Ci.nsILoadContext);
            } catch (ex2) {}
        }
    } catch (ex0) {}

    if (!loadContext) {
        //no load context so dont do anything although you can run this, which is your old code
        //this probably means that its loading an ajax call or like a google ad thing
        return null;
    } else {
        var contentWindow = loadContext.associatedWindow;
        if (!contentWindow) {
            //this channel does not have a window, its probably loading a resource
            //this probably means that its loading an ajax call or like a google ad thing
            return null;
        } else {
            var aDOMWindow = contentWindow.top.QueryInterface(Ci.nsIInterfaceRequestor)
                .getInterface(Ci.nsIWebNavigation)
                .QueryInterface(Ci.nsIDocShellTreeItem)
                .rootTreeItem
                .QueryInterface(Ci.nsIInterfaceRequestor)
                .getInterface(Ci.nsIDOMWindow);
            var gBrowser = aDOMWindow.gBrowser;
            var aTab = gBrowser._getTabForContentWindow(contentWindow.top); //this is the clickable tab xul element, the one found in the tab strip of the firefox window, aTab.linkedBrowser is same as browser var above //can stylize tab like aTab.style.backgroundColor = 'blue'; //can stylize the tab like aTab.style.fontColor = 'red';
            var browser = aTab.linkedBrowser; //this is the browser within the tab //this is where the example in the previous section ends
            return {
                aDOMWindow: aDOMWindow,
                gBrowser: gBrowser,
                aTab: aTab,
                browser: browser,
                contentWindow: contentWindow
            };
        }
    }
    //end loadContext stuff
}

also a note. because you want to change user request make sure that third parameter is set to false in httpChannel.setRequestHeader('MyCustomRequestHeader', 'hiiii', false); otherwise it will merge the pre-existing user agent with the new one you supply

Community
  • 1
  • 1
Noitidart
  • 35,443
  • 37
  • 154
  • 323
  • 1
    You'll get a null context when a background process (e.g. from an add-on) issues a http request which is unrelated to any specific browser tab. So yes, ignoring it in this case would be the most sensible approach. – Luckyrat Apr 06 '14 at 14:19
  • Thanks much for this reply I was eagerly waiting for someone to help us on this, but what situations have no tab? Just addons executing calls right? Any resource files loaded in tab will always have tab right? – Noitidart Apr 06 '14 at 21:09
  • There's no definitive list but addons would be a common one, and internal Firefox operations such as usage metrics collection, add-on update checks, automatic browser update downloads, downloading plugin block lists, etc. I don't know for certain that all of these things will go through the same code path that you're working with but if they do, they will have a null context. – Luckyrat Apr 06 '14 at 22:55
  • Got it thanks man! Is thre any time anything that loads within a tab has null loadContext? Like images or script files or ajax calls or something? That's what worries me. – Noitidart Apr 07 '14 at 02:53
  • 1
    No, that would have serious privacy implications since the context is used to track whether given requests are part of a private browsing session. Of course, there may be Firefox bugs or some add-ons that behave in this way and somehow slip past Mozilla's review process but it is very unlikely. – Luckyrat Apr 07 '14 at 07:43
  • 2
    Perfect! I was hoping everything in a tab always had context. Thanks man or the verification. – Noitidart Apr 07 '14 at 08:13
  • 1
    I have same exceptional cases from other extensions, and yes, if there is no context - ignoring is a good way. – msangel Dec 29 '15 at 01:44
  • Thanks @msangel for that info, if you can share some details that would be awesome! – Noitidart Dec 29 '15 at 03:44