AJAX Cross Domain

AJAX Cross Domain is a free library in Perl that allows to perform AJAX requests between different domains.


topSynopsis

<script type="text/javascript" src="https://www.ajax-cross-domain.com/cgi-bin/ACD/ACD.js?uri=(https://www.google.com)"></script> <script type="text/javascript"> alert(ACD.responseText); </script>

This alerts the source code of www.google.com. Run it here.


topMotivation

Virtually all modern server-side scripting languages support remote requests in one or another form. In client-side javascript, this functionality is not present due to the Same Origin Policy. Though this policy is necessary for a robust security model, programmers are often handicapped in their wish to send and retrieve requests to remote servers. During the last years, several proposals have been made for a more flexible (re-)design of the XMLHttpRequest object, which is the core mechanism of all AJAX based technologies. AJAX Cross Domain provides in the full functionality of the XMLHttpRequest object in a similar syntax, and can by extent handle all cross-domain requests. The core engine of AJAX Cross Domain is written in Perl and outputs its content as a javascript file.


topExamples

All code blocks are fully working cut-and-paste examples and can be directly used in your own test pages.

This example alerts the response body of an URL with a query-string (run it):

<script type="text/javascript" src="https://www.ajax-cross-domain.com/cgi-bin/ACD/ACD.js?uri=(http://qs4913.pair.com/dotserv/ACD/?name=john)"></script> <script type="text/javascript"> alert(ACD.responseText); </script>

This example does a remote request and shows all the response headers (run it):

<script type="text/javascript" src="https://www.ajax-cross-domain.com/cgi-bin/ACD/ACD.js?uri=(https://www.google.com/)"></script> <script type="text/javascript"> alert(ACD.getAllResponseHeaders); </script>

This example returns only a specific header of interest (run it):

<script type="text/javascript" src="https://www.ajax-cross-domain.com/cgi-bin/ACD/ACD.js?uri=(https://www.google.com/)"></script> <script type="text/javascript"> if (ACD.getResponseHeader['Content-Type']) { alert(ACD.getResponseHeader['Content-Type']); } </script>

This example performs a POST request to the given URI and shows the request how it was offered to the remote resource (run it):

<script type="text/javascript" src="https://www.ajax-cross-domain.com/cgi-bin/ACD/ACD.js?uri=(http://qs4913.pair.com/dotserv/ACD/runit/post.cgi)&amp;method=post&amp;postdata=(name=fred&amp;email=fred@fred.com)"></script> <script type="text/javascript"> alert(ACD.responseText); </script>

If postdata is present, it is assumed that the request method is meant as post even when method=post is not explicitly mentioned. The following example performs a (somewhat more complex percent-encoded) POST-request and returns the response body (run it):

<script type="text/javascript" src="https://www.ajax-cross-domain.com/cgi-bin/ACD/ACD.js?uri=(http://qs4913.pair.com/dotserv/ACD/runit/post.cgi)&amp;postdata=(name=John%20Johnson&amp;email=john@gmail.com&amp;company=C%26A%20%28until%20May%29&amp;sum=1%2B1%3D2)"></script> <script type="text/javascript"> alert(ACD.responseText); </script>

This example sends a request with header User-Agent set to My cool User-Agent and header Content-Language set to en, and shows the request that was offered to the remote server (run it):

<script type="text/javascript" src="https://www.ajax-cross-domain.com/cgi-bin/ACD/ACD.js?uri=(https://www.google.com)&amp;headers=(User-Agent=My%20cool%20User-Agent&amp;Content-Language=en)"></script> <script type="text/javascript"> alert(ACD.request); </script>

This example generates an error because uri is invalid (run it):

<script type="text/javascript" src="https://www.ajax-cross-domain.com/cgi-bin/ACD/ACD.js?uri=(http/www.google.com)"></script> <script type="text/javascript"> alert(ACD.error); </script>
 

topAttributes

uri

uri is the only required parameter and identifies the remote resource. The value of uri must be enclosed by brackets and needs to be a valid URI according to RFC 3986 with a percent-encoded query-string. Valid examples of uri are:
uri=(https://www.site.com/)
uri=(https://www.site.com?name=john&amp;email=john@hotmail.com)
uri=(https://www.site.com:8080?abc%20def)

Additionally, if left bracket or right bracket are needed in the query-string, they must be percent-encoded in order to distinguish them from the leading and trailing bracket. Although this is not required by RFC 3986, AJAX Cross Domain needs those to mark the begin and end. For example:
uri=(https://www.site.com/index.php?leftbracket=%28&amp;rightbracket=%29)
For the same reason, the equals sign ("=") should be escaped as %3D, and the ampersand ("&") as %26 when they are not used as delimiters towards the end resource. See the section Escape Sequences of this document for further details about percent-encoding.

method

The method attribute is optional and has two possible values: get and post.
method=get is used to perform a get request. This should be the most common option. If no method attribute is given, AJAX Cross Domain defaults to method=get as well.
method=post is used to perform a post request. This is typically done for larger data, though AJAX Cross Domain is limited to maximum 2083 bytes (which should suffice for most posted data though). Posted data is always offered to the remote resource in the default application/x-www-form-urlencoded encoding type.
Some resources may demand a Content-Length header before accepting post requests.

postdata

postdata holds the data to be posted to the remote resource when using method=post. A valid example of postdata is:
postdata=(name=fred&amp;email=fred@fred.com)
If the postdata attribute is given and method is absent, AJAX Cross Domain will assume that the request should be done using post anyway. No binary data can be offered, unless you manage to encode it into an URL that stays under 2KB (typically using Base64), and decode it back at the remote resource. Data should be percent-encoded as with uri; for more details see the section Escape Sequences. postdata is not a mandatory attribute even under method=post, since it might be desirable to post empty data.

headers

Optional attribute that indicates which headers should be sent together with the remote request. This can be anything you like. Valid examples of headers are:
headers=(Accept-Language=en&amp;Content-Type=text/xml)
headers=(from=info@ajax-cross-domain.com)

base64

Optional attribute only to be used when the response is to be Base64-encoded. Normally this is only necessary when outputting binary content. A valid example of base64 is:
base64=1
Any other value than 1 (or when base64 is kept away) will cause the response to not be Base64-encoded. You must use Base64 for all binary content. Run a demo with a JPG-file sent as binary (wrong) or encoded in Base64 (right).


topProperties and methods

The returned ACD object holds four properties and one method.

ACD.responseText

This property returns the full body of the response.

ACD.getAllResponseHeaders

This property returns the full header list of the response.

ACD.getResponseHeader

The ACD.getResponseHeader method holds the headers that were returned by the remote resource. For example, ACD.getResponseHeader['Content-Type'] and ACD.getResponseHeader['Date'] are available in most cases. In order to make sure that a property exists, you need to feature-detect it first (see section Examples).

ACD.request

This property shows the full request as it was fired to the remote resource.

ACD.error

This property shows any errors that might have occurred.


topEscape sequences

Characters with reserved and unreserved purpose

The fully formatted URI must be valid as defined by RFC 3986. The first part should just be the path to the program /cgi-bin/ACD.ACD.js? and doesn't need any escaping. The query-string (which begins just after the question mark) needs to be escaped using percent-encoding.

According to RFC 3986, the allowed characters are divided into reserved and unreserved characters.

The unreserved characters never need any percent-encoding:

ABCDEFGHIJKLMNOPQRSTUVWXYZ
abcdefghijklmnopqrstuvwxyz
0123456789-_.~

The reserved characters are listed in the table below, and need to be written as follows in AJAX Cross Domain:

Character Percent-encoding How to write in ACD query-string
! %21 Both
* %2A Both
' %27 Both
( %28 ( in reserved purpose and %28 outside reserved purpose [*]
) %29 ) in reserved purpose and %29 outside reserved purpose [*]
; %3B Both
: %3A : in reserved purpose and %3A outside reserved purpose
@ %40 @
& %26 &amp; in reserved purpose and %26 outside reserved purpose
= %3D = in reserved purpose and %3D outside reserved purpose
+ %2B %2B
$ %24 Both
, %2C Both
/ %2F / in reserved purpose and %2F outside reserved purpose
? %3F ? right behind ACD.js, otherwise %3F
% %25 %25
# %23 %23
[ %5B Both
] %5D Both

[*] Must always be percent-encoded inside the uri, headers and postdata attributes, see section "Escape of left and right brackets" below.

AJAX Cross Domain also understands the following ASCII characters of which RFC 2396 states that it is unwise to use them (so, it would be preferred to escape those as well):

<>\^`{}|

The double quote (") must always be escaped to %22 because it is used by <script src> as enclosing character.

Non-percent-encoded characters &, < and > must always be written as respectively &amp;, &lt; and &gt; when ACD.js is called from any HTML file.

No other characters may be used except those mentioned here. Characters outside of the ASCII-range are never supported in URI's.

Example escape sequences

uri=(https://www.site.com/)
Right, because / and : cannot be escaped here since they are used with a reserved purpose.

uri=(https://www.site.com/search.asp?q=test)
Right, because the last = resides inside the brackets of uri.

headers=(Content-Type=text/xml&amp;uri=(https://www.site.com)
Wrong, because the right bracket is missing after /xml. The right writing would be:
headers=(Content-Type=text/xml)&amp;uri=(https://www.site.com)

uri=(https:/%2Fwww.site.com/app.php?q=test)
Wrong, because / has a reserved purpose here. The right writing would be:
uri=(https://www.site.com/app.php?q=test)

uri=%28https://www.site.com/)
Wrong, because left-bracket has a reserved purpose here and cannot be percent-encoded. The right writing is:
uri=(https://www.site.com/)

Additional notes

Escape of left and right brackets

Inside the uri, headers and postdata attributes, left and right bracket are used to indicate the beginning and the end of the value. This means that these characters cannot be used as such inside the value of these attributes itself. Therefore, it is mandatory to escape them as follows:

https://www.site.com?(
becomes in ACD:
uri=(https://www.site.com?%28)

https://www.site.com?%28
becomes in ACD:
uri=(https://www.site.com?%2528)

bracket=)&amp;encodedbracket=%29
becomes in ACD:
postdata=(bracket=%29&amp;encodedbracket=%2529)

For all other characters, the original encoding is untouched. For example:
uri=(https://www.site.com?q=%3D+*&amp;hl=de&amp;otherchars=%2F^%28%22'!$%23)
remains identical.


topFlowchart


 


topRemarks


topSecurity issues

Though a default installation of AJAX Cross Domain should be pretty safe, it is important to understand the involved security issues.

Calling ACD.js is only allowed with certain query-strings (main rule)

A web page that attempts to call ACD.js, will only succeed if the offered query-string is allowed by ACD.js itself. In the top of the source code, the array @allowed_uris is used to define which query-strings are allowed and which aren't. This is a necessary safety restriction, because otherwise any web page can use your ACD.js installation to perform any request.
More details how to set @allowed_uris can be found in the Installation procedure. The examples on this web site use the same safety mechanisms; so that not any remote resource can be called.

Authentication of ACD.js against the remote resource (optional rule)

If your remote resource needs some form of authentication, it is important to realize that this must come from information stored in the query-string or based on the origin of ACD.js. If you have control over the remote resource, it is more recommended to use the second rather than the first. The former will always remain vulnerable because any call of ACD.js can always be deducted with its full query-string by anyone who has access to the main caller file. You can filter on the domain name and/or IP-address of ACD.js by using mod_authz_host.


topInstallation procedure

All common variants of UNIX are supported as long as they are set up with Perl5+ and the Apache web server (both should normally be present by default). Your FTP account or web server must be set up with a cgi-bin directory or otherwise be configured with the possibility to execute Perl scripts. The procedure below refers to the cgi-bin directory as this is the most common place where Perl files are stored and executed; but this can be any location that supports it.

  1. Save the AJAX Cross Domain source code to your local hard disk.

  2. Go to the CGI-enabled directory of your web site (typically named cgi-bin) and create a subdirectory named ACD there.

  3. Upload the source code to /cgi-bin/ACD/ and rename it to ACD.js.

  4. Give the file the necessary execution rights: open a Telnet or SSH session and type chmod 755 ACD.js when in the directory where ACD.js was stored. Alternatively, most (S)FTP programs support the chmod command too; the rights should be set at read+write+execute for owner (rwx), read+execute for group (r-x) and read+execute for nobody (r-x), in short 755.

  5. Now we need to tell Apache that .js extensions need to be ran as CGI. While still in the same directory, create a file named .htaccess with the following content:

    Options +ExecCGI AddType cgi-script js AddHandler cgi-script js

    These directives instruct Apache to serve .js files as CGI from the ACD-directory.

  6. Your installation of AJAX Cross Domain is now complete. Create a web page test.htm with the following content:

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "https://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>ACD test page</title> <script type="text/javascript" src="/cgi-bin/ACD/ACD.js?uri=(https://www.google.com)"></script> <script type="text/javascript"> alert(ACD.responseText); </script> </head> <body>&nbsp;</body> </html>

    Upload test.htm to your web site and run it from your browser. This should give you an alert window with the source code of Google. Note that this web page only works because the query-string is already present in @allowed_uris inside your ACD.js file.

  7. In your test.htm file, replace www.google.com by your own preferred remote resource. Then, add this resource in @allowed_uris inside the source of ACD.js.

  8. See Attributes to start crafting your own query-string. Write your own javascript code at wish to further parse the remote response. See section Properties and methods or use any of the Examples for a quick start.

AJAX Cross Domain works under Microsoft-based servers as well when they run ActivePerl. The chmod-command or .htaccess directives are usually not present there. If you're planning to install AJAX Cross Domain on any non-UNIX system, please refer to the manual of your Operating System how to assign file permissions, how to install Perl programs, and how to make .js extensions execute as CGI. Unfortunately, we can not give any guarantees for non-UNIX systems.


topSource code

Download as txt file.


topApplication

To give you a few ideas what AJAX Cross Domain can do for you:


topBugs

Send an e-mail to info@ajax-cross-domain.com.


topThanks

Thanks to Thomas Lahn, Dr John Stockton, Anthony Di Loreto and Ben Hines for bug tracking, testing, and general feedback.


topDisclaimer

This software is provided by myKMO, Ltd., "as is" and any express or implied warranties, including, but not limited to, the implied warranties of merchantability and fitness for a particular purpose are disclaimed. In no event shall the author and/or myKMO, Ltd., be liable for any direct, indirect, incidental, special, exemplary, or consequential damages (including, but not limited to, procurement of substitute goods or services; loss of use, data or profits; or business interruption) however caused and on any theory of liability, whether in contract, strict liability, or tort (including negligence or otherwise) arising in any way out of the use of this software, even if advised of the possibility of such damages. Should the software prove defective, you assume the cost of all necessary servicing, repair or correction. All of our rights, duties, and obligations are subject to the courts of the Kingdom of Belgium only.


topAuthor

bart_van_der_donck.jpg

Written and maintained by Bart Van der Donck 2008-2024.
Commercial software services are also available.


Page counter since 10-Dec-07: 700186 (Google Analytics)
Page last updated: Saturday, 31-Aug-24 21:42:58 CEST