Unlike the Greasemonkey extension in Mozilla, Opera does not provide an analogue of the GM_xmlhttpRequest function for cross-domain requests (XDR). This, of course, severely limits the capabilities and scope of UserJS. Using XDR, for example, you can implement an Last.fm scrobbler for various online music players (such as vkontakte.ru or MySpace).
However, cross-domain queries can be made to work in Opera with tricks with iframes and window.name transport. Under the cut, I'll show you how to do it and present a simple library that implements all witchcraft.
Generally speaking, the following techniques are used for cross-domain queries:
- Proxy requests. If we own a server whose pages want to access a remote web service, you can implement a script on our server that proxies requests to it. Thus, on the client side, the requests will look like an appeal to your domain, and in fact, the results of the query on the remote server will be returned.
The disadvantages of this approach, in addition to the need to control the server on the requesting domain, include the load on the incoming channel of our server and the possibility of banning our proxy by IP. In addition, user data passes through our server, so the end user must trust us. - Requests via Flash. In the case when we own a server that provides a web service, we can place an XML policy file on it, allowing their XDR from some domains. Cons: control of the web service is required, Flash is required.
- The use of various kinds of substitutes for asynchronous requests, such as the dynamic generation of
script
elements. Required control over the web service. In addition, a more or less serious change in its code is required to return the correct javascript. - Use Cross-Origin Resource Sharing . Again, control of the web service is required, and in addition this specification, as far as I know, is not supported anywhere else.
If anyone is interested, someday I will write in detail about these classical approaches. But they are already written in many places.
')
When writing UserJS, in general, we do not have access to either the server, on the page of which the script is launched, or to the web service. Therefore, we cannot use any of the above techniques in their pure form. But there is a way to overcome these limitations.
The essence of the method
It would seem that everything is simple: the request is made from iframe from the domain of the web service, and the main page with the frame communicates using the window.name transport. Recall that the window.name property, once set, retains its value when traveling through a window across a domain.
Now more. So, suppose we write UserJS for
domain.ru
, which wants to make an asynchronous request to a web service on the
ws.org
domain. Requests to the web service will be sent to the UserJS running in the iframe for a document from the
ws.org
domain (say,
ws.org/dummy.gif
: which particular URL is not important). And in order to pass the request arguments, it is necessary in advance, before the page opens from the remote domain, to set
window.name
on the frame in the string containing these parameters. Thus, the UserJS on ws.org will receive the request arguments from its window.name and send the necessary XMLHttpRequest to
ws.org
. It is already possible for him: a request within the ws.org domain. Then the result of execution is thrust again into the
window.name
frame, and the frame will be redirected to any page on
domain.ru
(for example,
domain.ru/dummy2.gif
), where UserJS is running again, which starts the result result handler in the main window.
Of course, you need to choose
dummy.gif
documents and
dummy2.gif
, which have the correct caching headers, because every request passes through them.
On the diagram, it looks like this:

By the way, it is necessary to remember that each browser window (and iframe is a window) executes a separate javascript stream. To run the handler in the context of the main window's thread, you can use something like the
window.parent.setTimeout(parent.handler, 0)
construct. The point, I think, is clear.
Application
I implemented this method as a self-made library to make
last.fm scrobbler for vkontakte.ru .
Implementation can be viewed
on pastebin . On line 58 was a pastebin's glitch glitch, so I commented out it. It, of course, must be uncommented when used.
All the work is done by the object
Requester
.
Requester.request
sends the request. He needs to pass the address of the web service page, on which the request will subsequently be executed, and the address on his domain (that is,
dummy.gif
and
dummy2.gif
from the example). The
request
method creates an iframe, passes the parameters, and translates the iframe to
dummy.gif
. It returns the Deferred-object, on which you can attach callback and errback (errback will be called upon timeout). UserJS at
ws.org/dummy.gif
can get passed parameters from
Requester.getArguments()
and return data using
Requester.returnData()
. With token,
Requester
verifies that the data is meant for it. That is, if there is a possibility of several scripts on one web service, you should change the token to any other.
A working script using
Requester
is
here .