Read More...

Performing HTTP/HTTPS requests in a Chrome Extension

January 23, 2017 · 2 min read

When building a Chrome extension, you can make cross-site XMLHttpRequests via Content Scripts or the Background Page.

Content Scripts is JavaScript that can get injected into a webpage and can manipulate the page’s DOM. On the other hand, the Background Page is like a home page for your Chrome Extension that does it’s own thing. It cannot interact directly with the webpage you are viewing.

The extension I was building needed to extract text from a webpage and save it into my web server. I injected JavaScript from my Content Scripts, that allowed me to get the text on a webpage I double-clicked on. Then the text needed to be sent to my web server to perform further actions via a POST request.

The XMLHttpRequest can be done from the Content Scripts, but there is one caveat. If the webpage you are interacting with is loaded via HTTPS, the request has to be done to an API endpoint that is loaded via HTTPS as well. Let’s say I wanted to save a piece of text from the Guardian to my web server that is running on http://localhost:3000. If I performed a request from the Guardian which is secured by HTTPS to a localhost run on HTTP, you will receive the following error.

Mixed Content: The page at ‘https://www.theguardian.com/football/2017/jan/21/pep-guardiola-spurs-draw-penalty-raheem-sterling-missed-chances' was loaded over HTTPS, but requested an insecure XMLHttpRequest endpoint ‘http://localhost/api/word'. This request has been blocked; the content must be served over HTTPS.

To get around that, you can setup your localhost to run on HTTPS but performing the request from the Background Page is an option as well. Content Scripts and the Background Page can communicate to each other by sending messages like sockets.

On the Content Script, you can send the info you need to the Background page like the following:

chrome.runtime.sendMessage({ message: ‘save_text’, data });
// data is the text I extracted from the webpage

On the Background Page, you just need a listener to watch for it.

const saveExtractedText = data => {
  $.post('http://localhost:3000/api/endpoint', data)
}
chrome.runtime.onMessage.addListener((request, sender, senderResponse) => {
  switch (request.message) {
    case 'save_text': {
      saveExtractedText(request.data)
      break
    }
    default:
  }
})

In this fashion, you can perform XMLHttpRequest to a HTTP endpoint, which is nice when you are developing something locally and just want to test things out.