How to make a POST request using AJAX in a Chrome Extension?

17,483

Solution 1

Here was the solution I had:

manifest.json:

{
    "manifest_version": 2,
    "name": "My Name",
    "description": "My Description.",
    "version": "0.1",
    "background": 
    {
        "scripts": ["jquery.js","background.js"],
        "persistent": true
    },
    "permissions": 
    [
        "tabs",
        "storage"
    ],
    "browser_action": 
    {
        "default_icon": "icon.png",
        "default_popup": "popup.html"
    },
    "content_scripts": 
    [
        {
            "matches": ["https://www.myurl.com/*"],
            "js": ["jquery.js","popup.js"],
            "run_at": "document_end"
        }
    ]
  }

background.js:

var learnerid=0;
// Called when the user clicks on the browser action.
chrome.tabs.onUpdated.addListener
( 
    function (tabId, changeInfo, tab) 
    {
        if (changeInfo.status == 'complete') 
        {
            chrome.tabs.query
            (
                { 
                    active: true 
                }, 
                function (tabs) 
                {
                    if(learnerid!=0)
                    {
                        TrackURL(tabs);
                    }
                    else
                    {
                        console.log("User not logged in yet!");
                    }//end if
                }
            );//end query
        }
    }
);

chrome.runtime.onMessage.addListener
(
    function(message, sender, sendResponse) 
    {
        if(message.applicationcode=="appname")
        {
            learnerid=message.learnerid;
        }//end if
    }
);//end function


function TrackURL(tabs)
{
    $.ajax
    (
        {
            type: "POST",
            url: "http://www.myurl.com/action.php",
            dataType:"json",
            data: 
            {               
                Action: 'TrackURL',
                URL:tabs[0].url,
                Title:tabs[0].title,
                LearnerID:learnerid
            },
            success: function(msg)
            {
                console.log("URL Tracked");
            }//end function
        }
    );//End ajax 

}//end function

popup.js:

document.addEventListener
(
    "starttrack", 
    function(e) 
    {
        startPoll(e.detail);
    }
); 


function startPoll(e)
{
    chrome.runtime.sendMessage
    (
        {
            applicationcode: "myapp",
            learnerid: e,
        }
    ); 
}

From my webpage:

function SendLearnerID(value)
                  {
                    try
                    {

                        var event = new CustomEvent("starttrack",{'detail': value});
                        document.dispatchEvent(event);
                    }
                    catch(err) 
                    {
                        console.log(err);
                    }   

                  }//end function

My problem was where my original event call happened, from within the web page....hence the 406 error. Hope this helps someone else.

Solution 2

Cause:

Luckily you're right... you are only missing something simple:

You need permissions for ANY and EVERY page/domain/URL you want this to work on, and you have only requested permissions for www.mywebpage.com in your current manifest.json:

    "permissions": [
      "tabs","http://www.mywebpage.com/*","https://www.mywebpage.com/*"
    ],

Solution:

If you want to do this within the context of the background page/script, you need to add all URLs in the permissions entry in your manifest.json. If you want to do this from a content script, then you need to add it in the content_scripts entry. If you plan on doing it in both places, then add in both entries/sections:

    "permissions": [                //needed for background script
      "tabs","http://*/*","https://*/*"
    ],
    "content_scripts":[             //needed for content script
      ...
      "http://*/*","https://*/*"
      ...
    ]

if you would also like the user to be able to use your extension when opening local files too, then add that a permission for the file schema/protocol, like so:

    "permissions": [                //needed for background script
      "tabs","http://*/*","https://*/*","file://*/*"
    ],
    "content_scripts":[             //needed for content script
      ...
      "http://*/*","https://*/*"
      ...
    ]
Share:
17,483
ProgrammerWannabe
Author by

ProgrammerWannabe

Just your average karate instructor/computer nerd. Who happens to have a hot wife!

Updated on June 24, 2022

Comments

  • ProgrammerWannabe
    ProgrammerWannabe almost 2 years

    I am attempting to make an ajax call when the browser is on my webpage it works perfectly but as soon as I leave my domain, it fails. This is for a closed system that user knows they are being tracked so nothing shady going on. I am receiving an error 406 on everything outside of my domain. For example if I on my url of www.mywebpage.com the script executes perfectly, but as soon as I visit www.yourwebpage.com it returns the error.

    I have tried setting the permissions in the manifest.json to my URL, all urls, specific urls but it behaves the same way. Here is my background.js

    chrome.runtime.onMessage.addListener
    (
        function(message, sender, sendResponse) 
        {
            if(message.applicationcode=="VALIDAPPLICATIONKEY")
            {
                var salt=message.salt;
                var learnerid=message.learnerid;
                var behaviorkey=message.behaviorkey;
                var behaviorname=message.behaviorname;
                var behaviorkeyname=message.behaviorkeyname;
                chrome.tabs.query
                (
                    {active: true}, 
                    function(arrayOfTabs) 
                    {
                        var data = new FormData();
                        data.append('Salt', salt);
                        data.append('LearnerID', learnerid);
                        data.append('BehaviorKey', behaviorkey);
                        data.append('BehaviorName', behaviorname);
                        data.append('BehaviorKeyName', behaviorkeyname);
                        data.append('BehaviorValue', arrayOfTabs[0].url);
                        var xhr = new XMLHttpRequest();
                        xhr.open('POST', 'https://www.mywebpage.com/myservice.php', true);
                        xhr.onreadystatechange = function() 
                        {
                            if (xhr.readyState == 4) 
                            {
                                // JSON.parse does not evaluate the attacker's scripts.
                                var resp = JSON.parse(xhr.responseText);
                                console.log(resp);
                            }
                        }
                        xhr.send(data);     
                    }
                );//end query
                return true;
            }
        }
    );//end listener
    

    Here is my current manifest file.

    {
        "manifest_version": 2,
        "name": "Application",
        "description": "Plugin",
        "version": "1.0",
        "background": 
        {
            "scripts": ["jquery.js","background.js"],
             "persistent": true
        },
        "permissions": [
            "tabs","http://www.mywebpage.com/*","https://www.mywebpage.com/*"
    
        ],
        "browser_action": 
        {
            "default_icon": "icon.png",
            "default_popup": "popup.html"
        },
        "content_scripts": 
        [
            {
                "matches": ["<all_urls>"],
                "js": ["jquery.js","popup.js"]
            }
        ]
    }
    

    Any thoughts or help on this would be greatly appreciated. According to the documentation here what I am trying to do is allowed by extensions and does work in a limited fashion. Or should this type of action being taking place in the extension page as suggested here? I am new to writing Chrome extensions and I am sure I am missing something stupid.

    Thanks in advance.