Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Chrome Extension Development - POST to new tab

Is there an easy solution to POST dynamically aggregated data into a new tab?

chrome.tabs.create does not have a 'POST' option. Normally I would use

chrome.browserAction.onClicked.addListener(function (t) {
  chrome.tabs.create(
  {
    "url" : "http://super.url",
    "method" : "POST" // oops.. no option.
  });
});
like image 714
Pono Avatar asked Sep 12 '11 11:09

Pono


3 Answers

You can simply combine these two techniques:

  1. You may execute JavaScript commands by adding javascript: prefix at your address bar or in href values of <a> tags.
  2. Only with JavaScript, you can create a form element and fill it with your data then POST it.
function fakePost() {
    var form = document.createElement("form");
    
    // Create a POST dump at ptsv2.com and change the code
    form.setAttribute("action", "http://ptsv2.com/t/dcgex-1614815819/post");
    form.setAttribute("method", "post");

    var params = { userId: 2, action: "delete" };
    for(var key in params) {
        var hiddenField = document.createElement("input");
        hiddenField.setAttribute("type", "hidden");
        hiddenField.setAttribute("name", key);
        hiddenField.setAttribute("value", params[key]);
        form.appendChild(hiddenField);
    }

    // Appending the form might not be necessary
    document.body.appendChild(form);

    form.submit();
};

const 
    source = fakePost.toString().replace(/(\n|\t)/gm,'').replace(/\s\s/gm,' '),
    url = `javascript:${source}; fakePost();`;

chrome.browserAction.onClicked.addListener(() => chrome.tabs.create({ url }));

Of course, that's just a dirty hack. If you need something more elaborate you can use a XHR Object or @Xan's answer.

like image 185
kbtz Avatar answered Sep 28 '22 02:09

kbtz


The code in cvsguimaraes' answer works for short data strings, that can fit into a URL. As evidenced by this question, it's not always the case.

Kenny Evitt's answer hints at the solution. I made an implementation for that question, and took time to generalize it. I present it here.

The idea is to open a page bundled with the extension (post.html), supply it with required information via messaging, and perform the POST from that page.

post.html

<html>
  <head>
    <title>Redirecting...</title>
  </head>
  <body>
    <h1>Redirecting...</h1>
    <!-- Decorate as you wish, this is a page that redirects to a final one -->
    <script src="post.js"></script>
  </body>
</html>

post.js

var onMessageHandler = function(message){
  // Ensure it is run only once, as we will try to message twice
  chrome.runtime.onMessage.removeListener(onMessageHandler);

  // code from https://stackoverflow.com/a/7404033/934239
  var form = document.createElement("form");
  form.setAttribute("method", "post");
  form.setAttribute("action", message.url);
  for(var key in message.data) {
    var hiddenField = document.createElement("input");
    hiddenField.setAttribute("type", "hidden");
    hiddenField.setAttribute("name", key);
    hiddenField.setAttribute("value", message.data[key]);
    form.appendChild(hiddenField);
  }
  document.body.appendChild(form);
  form.submit();
}

chrome.runtime.onMessage.addListener(onMessageHandler);

background.js (or other non-content script inside the extension)

function postData(url, data) {
  chrome.tabs.create(
    { url: chrome.runtime.getURL("post.html") },
    function(tab) {
      var handler = function(tabId, changeInfo) {
        if(tabId === tab.id && changeInfo.status === "complete"){
          chrome.tabs.onUpdated.removeListener(handler);
          chrome.tabs.sendMessage(tabId, {url: url, data: data});
        }
      }

      // in case we're faster than page load (usually):
      chrome.tabs.onUpdated.addListener(handler);
      // just in case we're too late with the listener:
      chrome.tabs.sendMessage(tab.id, {url: url, data: data});
    }
  );  
}

// Usage:
postData("http://httpbin.org/post", {"hello": "world", "lorem": "ipsum"});

Note the double messaging: with chrome.tabs.create callback we can't be sure that the listener is ready, nor can we be sure it's not done loading yet (though in my testing, it's always still loading). But better safe than sorry.

like image 20
Xan Avatar answered Sep 28 '22 03:09

Xan


From @Amman Cheval's comments on the question:

[send] your dynamic data to the background file, creating a new tab which includes a form. Fill up the form using your form using the content using the background file, and then submit the form.

Read up about content scripts on Google's docs first. Then read up on message passing. After you've understood all of that, it'd be fairly simple to send a message from the script, to the background, and to the script of a different tab.

like image 41
Kenny Evitt Avatar answered Sep 28 '22 03:09

Kenny Evitt