28

I am trying to play an audio using Google Text-To-Speech. Therefore I need to post a request to their endpoint with the Referer and the User-Agent properly set. This call should return an MP3 that I can play.

However, I get Refused to set unsafe header errors. This is my code. How can I do this?

          $.ajax({
            url: 'http://translate.google.com/translate_tts?ie=UTF-8&q=Hello&tl=en&client=t',
            beforeSend: function(xhr) {
                 xhr.setRequestHeader("Referer", "http://translate.google.com/");
                 xhr.setRequestHeader("User-Agent", "stagefright/1.2 (Linux;Android 5.0)");
            }, success: function(data){
                el.mp3 = new Audio(data);
                el.mp3.play();
            }
          });
Serge Stroobandt
  • 24,143
  • 8
  • 98
  • 91
  • Possible duplicate of [Add Header in AJAX Request with jQuery](http://stackoverflow.com/questions/10093053/add-header-in-ajax-request-with-jquery) – Craicerjack Oct 15 '15 at 08:48
  • 1
    Doesn't matter what header you set, the Google translate endpoint doesn't support CORS – adeneo Oct 15 '15 at 08:49
  • 1
    From cURL it works... –  Oct 15 '15 at 08:51
  • 4
    @Arturo — For cURL you are making the request yourself, you aren't asking your visitor's browser to quietly do it in the background on your behalf. There are lots of extra security restrictions when you try to make other people's browsers do things. – Quentin Oct 15 '15 at 08:57

2 Answers2

44

You can't. It is impossible.

The specification requires that the browser abort the setRequestHeader method if you try to set the Referer header (it used to be that User-Agent was also forbidden but that has changed)..

If you need to set Referer manually then you'll need to make the request from your server and not your visitor's browser.

(That said, if you need to be deceptive about the user agent or referer then you are probably trying to use the service in a fashion that the owner of it does not want, so you should respect that and stop trying).

Note that while jQuery wraps XHR, the same rules apply to fetch.

Quentin
  • 857,932
  • 118
  • 1,152
  • 1,264
1

Empty Origin and Referer headers with GET XMLHttpRequest from <iframe>

Well actually, it is possible; at least for ordinary web pages. The trick consists in injecting an XMLHttpRequest function into an empty <iframe>. The origin of an empty <iframe> happens to be about://blank, which results in empty Origin and Referer HTTP headers.

HTML:

<iframe id="iframe"></iframe>

JavaScript:

const iframe    = document.getElementById('iframe');
const iframeWin = iframe.contentWindow || iframe;
const iframeDoc = iframe.contentDocument || iframeWin.document;

let script = iframeDoc.createElement('SCRIPT');

script.append(`function sendWithoutOrigin(url) {
    var request = new XMLHttpRequest();

    request.open('GET', url);

    request.onreadystatechange = function() {
        if(request.readyState === XMLHttpRequest.DONE) {
            if(request.status === 200) {
                console.log('GET succeeded.');
            }
            else {
                console.warn('GET failed.');
            }
        }
    }
    request.send();
}`);

iframeDoc.documentElement.appendChild(script);

JavaScript evocation:

var url  = 'https://api.serivce.net/';
    url += '?api_key=' + api_write_key;
    url += '&field1=' + value;

iframeWin.sendWithoutOrigin(url);

Having the possibility of sending empty Origin and Referer HTTP headers is important to safeguard privacy when using third-party API services. There are instances where the originating domain name may reveal sensitive personal information; like being suggestive of a certain medical condition for example. Think in terms of https://hypochondriasis-support.org :-D

The code was tested by inspecting the requests in a .har file, saved from the Network tab in the F12 Developer View in Vivaldi.

No attempt in setting the User-Agent header was made. Please, comment if this also works.

Serge Stroobandt
  • 24,143
  • 8
  • 98
  • 91