CORS tests submitted by Opera Software
authorOdin Hørthe Omdal <odinho@opera.com>
Thu, 15 Dec 2011 18:49:07 +0100
changeset 15 8a0775f6d0eb
parent 14 8b07f915c023
child 16 8c4f146655aa
CORS tests submitted by Opera Software
tests/cors/submitted/opera/README.txt
tests/cors/submitted/opera/interactive/file-preflight.htm
tests/cors/submitted/opera/js/basic.htm
tests/cors/submitted/opera/js/credentials-flag.htm
tests/cors/submitted/opera/js/errors-async.htm
tests/cors/submitted/opera/js/errors-sync.htm
tests/cors/submitted/opera/js/https.htm
tests/cors/submitted/opera/js/origin.htm
tests/cors/submitted/opera/js/preflight-cache.htm
tests/cors/submitted/opera/js/redirect-preflight.htm
tests/cors/submitted/opera/js/redirect.htm
tests/cors/submitted/opera/js/request.htm
tests/cors/submitted/opera/js/resources/.hgignore
tests/cors/submitted/opera/js/resources/checkandremovefromlog.php
tests/cors/submitted/opera/js/resources/cors-cookie.php
tests/cors/submitted/opera/js/resources/cors-headers.php
tests/cors/submitted/opera/js/resources/cors-makeheader.php
tests/cors/submitted/opera/js/resources/log.php
tests/cors/submitted/opera/js/resources/preflight.php
tests/cors/submitted/opera/js/resources/status.php
tests/cors/submitted/opera/js/response.htm
tests/cors/submitted/opera/js/simple-requests.htm
tests/cors/submitted/opera/js/status-async.htm
tests/cors/submitted/opera/js/status-basic.htm
tests/cors/submitted/opera/js/status-preflight.htm
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/cors/submitted/opera/README.txt	Thu Dec 15 18:49:07 2011 +0100
@@ -0,0 +1,18 @@
+Cross Origin Resource Sharing tests submitted by Opera Software
+
+These tests assume that they also reside on:
+
+    http://<your domain>
+    http://crosssite.<your domain>
+    http://<your domain>:8081
+
+    https://<your domain>
+    https://<your domain>:8443
+
+
+
+js/
+    Automated javascript tests
+
+interactive/
+    Tests needing manual intervention
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/cors/submitted/opera/interactive/file-preflight.htm	Thu Dec 15 18:49:07 2011 +0100
@@ -0,0 +1,53 @@
+<!doctype html>
+    <meta charset=utf-8>
+    <title>Preflight on Content-Type set by xhr.send()</title>
+    <script src="/resources/testharness.js"></script>
+    <!-- Nah, not automatic... <script src="/resources/testharnessreport.js"></script> -->
+
+<script>
+setup({ timeout: 600000 })
+
+var id          = "1_" + new Date().getTime(),
+    client      = new XMLHttpRequest(),
+    crossdomain = location.href.replace("://", "://crosssite.").replace(/\/[^\/]*$/, '/')
+
+var t = async_test('Preflight cache loaded', { timeout: 10000 })
+
+function testcase() {
+    client.open('POST', crossdomain +
+        '../js/resources/preflight.php?age=3600&ident=' + id )
+    file = document.querySelector("#file_input").files[0]
+
+    client.onreadystatechange = function() {
+        if (client.readyState != 4)
+            return
+
+        /* Send a checkup on the preflight */
+        client.open('GET',
+            '../js/resources/checkandremovefromlog.php?age=3600&ident=' + id )
+
+        client.onreadystatechange = t.step_func(function() {
+            if (client.readyState != 4)
+                return
+
+            assert_true(client.response == "1", "did a preflight")
+            t.done()
+        })
+        client.send()
+    }
+
+    client.send(file)
+}
+
+</script>
+
+
+<ol>
+    <li><p>Choose a picture (e.g. <code>opera/local_data.png</code>):
+        <form>
+            <input type=file id=file_input name=file>
+        </form>
+    <li><p>Click the button: <button onclick=testcase()>Test it!</button>
+</ol>
+
+<div id=log></div>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/cors/submitted/opera/js/basic.htm	Thu Dec 15 18:49:07 2011 +0100
@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>XMLHttpRequest: Basic CORS</title>
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+  </head>
+  <body>
+    <p>This shouldn't be tested inside a tunnel.</p>
+    <div id="log"></div>
+    <script>
+
+    function dirname(path) {
+        return path.replace(/\/[^\/]*$/, '/')
+    }
+
+    var crossdomain = "http://crosssite." + location.hostname
+    var port = "8081" // Extra port for http
+    var folder = dirname(location.pathname)
+
+
+    /*
+     * Basic usage
+     */
+
+    test(function() {
+        var client = new XMLHttpRequest()
+        client.open('GET', dirname(location.href) + 'resources/cors-headers.php', false)
+        client.send(null)
+
+        assert_equals(client.response, 'TEST')
+    }, 'same domain basic usage')
+
+    test(function() {
+        var client = new XMLHttpRequest()
+        client.open('GET', crossdomain + folder + 'resources/cors-headers.php', false)
+        client.send(null)
+
+        assert_equals(client.response, 'TEST')
+    }, 'crossdomain basic usage')
+
+    test(function() {
+        var client = new XMLHttpRequest()
+        client.open('GET', 'http://' + location.hostname + ":" + port + dirname(location.pathname) + 'resources/cors-headers.php', false)
+        client.send(null)
+
+        assert_equals(client.response, 'TEST')
+    }, 'same domain different port')
+
+    test(function() {
+        var client = new XMLHttpRequest()
+        client.open('GET', crossdomain + ":" + port + dirname(location.pathname) + 'resources/cors-headers.php', false)
+        client.send(null)
+
+        assert_equals(client.response, 'TEST')
+    }, 'crossdomain different port')
+
+    </script>
+ </body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/cors/submitted/opera/js/credentials-flag.htm	Thu Dec 15 18:49:07 2011 +0100
@@ -0,0 +1,115 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>XMLHttpRequest: CORS - withCredentials</title>
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+  </head>
+  <body>
+    <p>This shouldn't be tested inside a tunnel.</p>
+    <div id="log"></div>
+    <script>
+
+    var crossdomain = "http://crosssite." + location.host + location.pathname.replace(/\/[^\/]*$/, '/')
+    var url = crossdomain + 'resources/cors-cookie.php?ident='
+
+
+    /*
+     * widthCredentials
+     */
+
+    test(function () {
+        var id = new Date().getTime(),
+            client = new XMLHttpRequest()
+        client.open("GET", url + id, false)
+        client.send(null)
+        assert_equals(client.response, "NO_COOKIE");
+
+        client.open("GET", url + id, false)
+        client.send(null)
+        assert_equals(client.response, "NO_COOKIE")
+    }, 'Don\'t send cookie by default');
+
+    test(function () {
+        var id = new Date().getTime(),
+            client = new XMLHttpRequest()
+
+        client.open("GET", url + id, false)
+        client.withCredentials = true
+        client.send(null)
+        assert_equals(client.response, "NO_COOKIE");
+
+        /* We have cookie, but the browser shouldn't send */
+        client.open("GET", url + id, false)
+        client.withCredentials = false
+        client.send(null)
+        assert_equals(client.response, "NO_COOKIE")
+
+        /* Reads and deletes the cookie */
+        client.open("GET", url + id, false)
+        client.withCredentials = true
+        client.send(null)
+        assert_equals(client.response, "COOKIE")
+    }, 'Don\'t send cookie part 2');
+
+    test(function () {
+        var id = new Date().getTime(),
+            client = new XMLHttpRequest()
+
+        /* Shouldn't set the response cookie */
+        client.open("GET", url + id, false)
+        client.withCredentials = false
+        client.send(null)
+        assert_equals(client.response, "NO_COOKIE");
+
+        /* Sets the cookie */
+        client.open("GET", url + id, false)
+        client.withCredentials = true
+        client.send(null)
+        assert_equals(client.response, "NO_COOKIE")
+
+        /* Reads and deletes the cookie */
+        client.open("GET", url + id, false)
+        client.withCredentials = true
+        client.send(null)
+        assert_equals(client.response, "COOKIE")
+    }, 'Don\'t obey Set-Cookie when withCredentials=false');
+
+    function test_response_header(allow) {
+        test(function () {
+            var client = new XMLHttpRequest()
+            client.open('GET',
+                crossdomain + 'resources/cors-makeheader.php?credentials=' + allow,
+                false)
+            client.withCredentials = true;
+            assert_throws('NETWORK_ERR', function() { client.send() }, 'send')
+        }, 'Access-Control-Allow-Credentials: ' + allow + ' => should throw NETWORK_ERR (sync)')
+
+        var resp_test = async_test('Access-Control-Allow-Credentials: ' + allow + ' => should trigger onerror (async)')
+        resp_test.step(function() {
+            var client = new XMLHttpRequest()
+            client.open('GET',
+                crossdomain + 'resources/cors-makeheader.php?credentials=' + allow,
+                true)
+            client.withCredentials = true;
+            client.onload = resp_test.step_func(function() {
+                assert_unreached("onload")
+            })
+            client.onerror = resp_test.step_func(function () {
+                assert_equals(client.readyState, client.DONE, 'readyState')
+                resp_test.done()
+            })
+            client.send()
+        })
+    }
+
+    test_response_header('TRUE')
+    test_response_header('True')
+    test_response_header('"true"')
+    test_response_header('false')
+    test_response_header('1')
+    test_response_header('0')
+
+    </script>
+ </body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/cors/submitted/opera/js/errors-async.htm	Thu Dec 15 18:49:07 2011 +0100
@@ -0,0 +1,63 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>XMLHttpRequest: CORS - errors (async)</title>
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+  </head>
+  <body>
+    <p>This shouldn't be tested inside a tunnel.</p>
+    <div id="log"></div>
+    <script>
+
+    function dirname(path) {
+        return path.replace(/\/[^\/]*$/, '/')
+    }
+
+    var crossdomain = "http://crosssite." + location.hostname + dirname(location.pathname)
+
+    /*
+     * Error checking
+     */
+
+    ;(function() {
+        var test = async_test('CORS fail async, getting onerror')
+        test.step(function() {
+            var xhr = new XMLHttpRequest()
+            xhr.open('GET', crossdomain + 'resources/cors-makeheader.php?origin=none', true)
+            xhr.onerror = test.step_func(function(e) {
+                assert_equals(xhr.readyState, xhr.DONE, "readyState")
+                assert_equals(xhr.status, 0, "status")
+                test.done()
+            })
+            xhr.onload = test.step_func(function(e) {
+                assert_unreached("should never get a response")
+            })
+            xhr.send()
+        })
+    })();
+
+    ;(function() {
+        var test = async_test('CORS fail async, 1: onreadystatechange, 2: onerror')
+        test.step(function() {
+            var xhr = new XMLHttpRequest(),
+                passed = false
+            xhr.open('GET', crossdomain + 'resources/cors-makeheader.php?origin=none', true)
+            xhr.onreadystatechange = test.step_func(function(e) {
+                if (xhr.readyState > xhr.OPENED)
+                    assert_equals(xhr.status, 0, "status")
+
+                if (xhr.readyState == xhr.DONE)
+                    passed = true
+            })
+            xhr.onerror = test.step_func(function(e) {
+                assert_true(passed, 'readystate DONE should be done first')
+                test.done()
+            })
+            xhr.send()
+        })
+    })();
+
+    </script>
+ </body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/cors/submitted/opera/js/errors-sync.htm	Thu Dec 15 18:49:07 2011 +0100
@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>XMLHttpRequest: CORS - errors (sync)</title>
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+  </head>
+  <body>
+    <p>This shouldn't be tested inside a tunnel.</p>
+    <div id="log"></div>
+    <script>
+
+    function dirname(path) {
+        return path.replace(/\/[^\/]*$/, '/')
+    }
+
+    var crossdomain = "http://crosssite." + location.hostname + dirname(location.pathname)
+
+    /*
+     * Error checking
+     */
+
+    test(function() {
+        var client = new XMLHttpRequest()
+        client.open('GET', crossdomain + 'resources/cors-makeheader.php?origin=none', false)
+        assert_throws('NETWORK_ERR', function() { client.send() }, 'send');
+        assert_equals(client.status, 0, "status")
+        assert_equals(client.readyState, client.DONE, "readyState")
+    }, 'Failed sync cross origin request')
+
+    var t = async_test('Failed sync cross origin request: onreadystatechange')
+    t.step(function() {
+        var client = new XMLHttpRequest()
+        client.open('GET', crossdomain + 'resources/cors-makeheader.php?origin=none', false)
+        client.onreadystatechange = t.step_func(function() {
+            assert_equals(client.status, 0, "status")
+            if (client.readyState == client.DONE)
+                t.done()
+        })
+        assert_throws('NETWORK_ERR', function() { client.send() }, 'send');
+    });
+
+    </script>
+ </body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/cors/submitted/opera/js/https.htm	Thu Dec 15 18:49:07 2011 +0100
@@ -0,0 +1,97 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>XMLHttpRequest: CORS - https</title>
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+  </head>
+  <body>
+    <p>This shouldn't be tested inside a tunnel.</p>
+    <div id="log"></div>
+    <script>
+
+    function dirname(path) {
+        return path.replace(/\/[^\/]*$/, '/')
+    }
+
+    var crossdomain = "crosssite." + location.hostname
+    var url = "https://" + crossdomain + dirname(location.pathname)
+    var ports = "8443"
+
+    /*
+     * HTTPS
+     */
+    function testit(url, desc) {
+        console.log("opnar " + url, desc)
+        test(function() {
+            var client = new XMLHttpRequest()
+            client.open('GET', url, false)
+            client.send(null)
+
+            assert_equals(client.response, 'TEST', 'response')
+        }, desc + " (sync)")
+
+        var async = async_test(desc + " (async)")
+        async.step(function () {
+            var client = new XMLHttpRequest()
+            client.open('GET', url, true)
+            client.onload = async.step_func(function() {
+                assert_equals(client.response, 'TEST', 'response')
+                async.done()
+            })
+            client.onerror = async.step_func(function() {
+                assert_unreached('Got onerror')
+                async.done()
+            })
+            client.send(null)
+        })
+
+    }
+
+    testit('http://' + location.host + dirname(location.pathname) + 'resources/cors-headers.php',
+        'http same domain basic usage')
+    testit('https://' + location.host + dirname(location.pathname) + 'resources/cors-headers.php',
+        'https same domain basic usage')
+
+    testit(url + 'resources/cors-headers.php',
+        'https crossdomain basic usage')
+
+    testit('http://' + location.hostname + ":8081" + dirname(location.pathname) + 'resources/cors-headers.php',
+        'http same domain different port')
+    testit('https://' + location.hostname + ":" + ports + dirname(location.pathname) + 'resources/cors-headers.php',
+        'https same domain different port')
+
+    testit('http://' + crossdomain + ":8081" + dirname(location.pathname) + 'resources/cors-headers.php',
+        'http crossdomain different port')
+    testit('https://' + crossdomain + ":" + ports + dirname(location.pathname) + 'resources/cors-headers.php',
+        'https crossdomain different port')
+
+
+    test(function () {
+        var client = new XMLHttpRequest()
+        client.open("GET", url + '/resources/cors-cookie.php', false)
+        client.withCredentials = true
+        client.send(null)
+        assert_equals(client.response, "NO_COOKIE");
+
+        client.open("GET", url + '/resources/cors-cookie.php', false)
+        client.withCredentials = true
+        client.send(null)
+        assert_equals(client.response, "COOKIE");
+    }, 'https cross-origin cookie');
+
+    test(function () {
+        var client = new XMLHttpRequest()
+        client.open("GET", url + '/resources/cors-cookie.php', false)
+        client.send(null)
+        assert_equals(client.response, "NO_COOKIE");
+
+        client.open("GET", url + '/resources/cors-cookie.php', false)
+        client.send(null)
+        assert_equals(client.response, "NO_COOKIE")
+    }, 'https don\'t send cookie by default');
+
+
+    </script>
+ </body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/cors/submitted/opera/js/origin.htm	Thu Dec 15 18:49:07 2011 +0100
@@ -0,0 +1,91 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>XMLHttpRequest: CORS - Access-Control-Allow-Origin, various</title>
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+  </head>
+  <body>
+    <p>This shouldn't be tested inside a tunnel.</p>
+    <div id="log"></div>
+    <script>
+
+    function dirname(path) {
+        return path.replace(/\/[^\/]*$/, '/')
+    }
+
+    var crossdomain = "http://crosssite." + location.host + dirname(location.pathname)
+
+
+    /*
+     * Origin header
+     */
+    function shouldPass(origin) {
+        test(function () {
+            var client = new XMLHttpRequest()
+            client.open('GET', crossdomain
+                                + '/resources/cors-makeheader.php?origin='
+                                + encodeURIComponent(origin),
+                        false)
+            client.send()
+            r = JSON.parse(client.response)
+            var host = location.protocol + "//" + location.host
+            assert_equals(r['origin'], host, 'Request Origin: should be ' + host)
+        }, 'Allow origin: ' + origin.replace(/\t/g, "[tab]").replace(/ /g, '_'));
+    }
+
+    shouldPass('*');
+    shouldPass(' *  ');
+    shouldPass('	*');
+    shouldPass(location.protocol + "//" + location.host);
+    shouldPass(" "+location.protocol + "//" + location.host);
+    shouldPass(" "+location.protocol + "//" + location.host + "   	 ");
+    shouldPass("	"+location.protocol + "//" + location.host);
+
+
+    function shouldFail(origin) {
+        test(function () {
+            var client = new XMLHttpRequest()
+            client.open('GET', crossdomain
+                                + '/resources/cors-makeheader.php?origin='
+                                + encodeURIComponent(origin),
+                        false)
+            assert_throws('NETWORK_ERR', function() { client.send() }, 'send')
+        }, 'Allow origin: ' + origin + ' should throw NETWORK_ERR');
+    }
+
+    shouldFail(location.protocol + "//crosssite." + location.host)
+    shouldFail("//" + location.host)
+    shouldFail("://" + location.host)
+    shouldFail("ftp://" + location.host)
+    shouldFail("http:://" + location.host)
+    shouldFail("http:/" + location.host)
+    shouldFail("http:" + location.host)
+    shouldFail(location.host)
+    shouldFail(location.protocol + "//" + location.host + "?")
+    shouldFail(location.protocol + "//" + location.host + "/")
+    shouldFail(location.protocol + "//" + location.host + " /")
+    shouldFail(location.protocol + "//" + location.host + "#")
+    shouldFail(location.protocol + "//" + location.host + "%23")
+    shouldFail(location.protocol + "//" + location.host + ":80")
+    shouldFail(location.protocol + "//" + location.host + ", *")
+    shouldFail((location.protocol + "//" + location.host).toUpperCase())
+    shouldFail(location.protocol.toUpperCase() + "//" + location.host)
+    shouldFail("-")
+    shouldFail("**")
+    shouldFail("* *")
+    shouldFail("*" + location.protocol + "//" + "*")
+    shouldFail("*" + location.protocol + "//" + location.host)
+    shouldFail("* " + location.protocol + "//" + location.host)
+    shouldFail("*, " + location.protocol + "//" + location.host)
+    shouldFail("null " + location.protocol + "//" + location.host)
+    shouldFail('http://example.net')
+    shouldFail('null')
+    shouldFail('')
+    shouldFail(location.href)
+    shouldFail(dirname(location.href))
+    shouldFail(crossdomain)
+
+    </script>
+ </body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/cors/submitted/opera/js/preflight-cache.htm	Thu Dec 15 18:49:07 2011 +0100
@@ -0,0 +1,147 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>XMLHttpRequest: CORS - preflight cache</title>
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+  </head>
+  <body>
+    <p>This shouldn't be tested inside a tunnel.</p>
+    <div id="log"></div>
+    <script>
+
+    function dirname(path) {
+        return path.replace(/\/[^\/]*$/, '/')
+    }
+
+    var crossdomain = "http://crosssite." + location.host + dirname(location.pathname)
+
+    /*
+     * Cache
+     */
+
+    function did_preflight(expect, client, ident, settings) {
+        if(!settings)
+            settings = {}
+
+        set = {
+            method: 'method' in settings ? settings.method : 'GET',
+            extra: 'extra' in settings ? '&' + settings.extra : ''
+        }
+
+        client.open(set.method,
+                crossdomain + 'resources/preflight.php?ident=' + ident + set.extra,
+                false)
+        client.setRequestHeader('x-print', ident)
+        client.send()
+
+        client.open('GET', 'resources/checkandremovefromlog.php?ident=' + ident, false)
+        client.send()
+        assert_equals(client.response, expect === true ? '1' : '0', "did preflight")
+    }
+
+    /*
+     * Should run preflight
+     */
+    var test_c = 0;
+
+    test(function() {
+        test_c++;
+        var time = new Date().getTime()
+        var client = new XMLHttpRequest()
+        did_preflight(true, client, test_c + '_' + time)
+    },
+    'Test preflight')
+
+    test(function() {
+        test_c++;
+        var time = new Date().getTime()
+        var client = new XMLHttpRequest()
+
+        did_preflight(true, client, test_c + '_' + time)
+        did_preflight(false, client, test_c + '_' + time)
+    },
+    'preflight for x-print should be cached')
+
+    test(function() {
+        test_c++;
+        var time = new Date().getTime()
+        var client = new XMLHttpRequest()
+
+        did_preflight(true, client, test_c + '_' + time, {extra:'max_age=0'})
+        did_preflight(true, client, test_c + '_' + time, {extra:'max_age=0'})
+    },
+    'age = 0, should not be cached')
+
+    test(function() {
+        test_c++;
+        var time = new Date().getTime()
+        var client = new XMLHttpRequest()
+
+        did_preflight(true, client, test_c + '_' + time, {extra:'max_age=-1'})
+        did_preflight(true, client, test_c + '_' + time, {extra:'max_age=-1'})
+    },
+    'age = -1, should not be cached')
+
+    ;(function() {
+        test_c++;
+        var test = async_test("preflight first request, second from cache, wait, third should preflight again", { timeout: 4000 }),
+            time = new Date().getTime(),
+            dothing = function (url, msg, setrequest, func) {
+                client = new XMLHttpRequest(),
+                client.open('GET', url + test_c + time, true)
+                if (setrequest)
+                    client.setRequestHeader('x-print', msg)
+                client.onreadystatechange = test.step_func(function() {
+                    if(client.readyState >= 4) {
+                        assert_equals(msg, client.response)
+                        if (func)
+                            test.step(func)
+                    }
+                })
+                client.send()
+                console.log(client)
+            }
+
+        test.step(function() {
+            /* First cycle, gets x-print into the cache, with timeout 1 */
+            dothing(crossdomain + 'resources/preflight.php?max_age=1&ident=',
+            'first', true, function(){
+                test = test;
+
+                /* Check if we did a preflight like we expected */
+                dothing('resources/checkandremovefromlog.php?ident=',
+                '1', false, function(){
+                    test = test;
+                    dothing(crossdomain + 'resources/preflight.php?max_age=1&ident=',
+                    'second', true, function() {
+                        test = test;
+
+                        /* Check that we didn't do a preflight (hasn't gone 1 second yet) */
+                        dothing('resources/checkandremovefromlog.php?ident=',
+                        '0', false, function(){
+                            test = test;
+
+                            /* Wait until the preflight cache age is old (and thus cleared) */
+                            setTimeout(test.step_func(function(){
+                                dothing(crossdomain + 'resources/preflight.php?max_age=1&ident=',
+                                'third', true, function(){
+                                    test = test;
+
+                                    /* Expect that we did indeed do a preflight */
+                                    dothing('resources/checkandremovefromlog.php?ident=',
+                                    '1', false, function(){
+                                        test.done()
+                                    })
+                                })
+                            }), 1500)
+                        })
+                    })
+                })
+            })
+        })
+    })();
+
+    </script>
+ </body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/cors/submitted/opera/js/redirect-preflight.htm	Thu Dec 15 18:49:07 2011 +0100
@@ -0,0 +1,65 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>XMLHttpRequest: CORS - redirect with preflight</title>
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+  </head>
+  <body>
+    <p>This shouldn't be tested inside a tunnel.</p>
+    <div id="log"></div>
+    <script>
+
+    function dirname(path) {
+        return path.replace(/\/[^\/]*$/, '/')
+    }
+
+    var crossdomain = "http://crosssite." + location.hostname + dirname(location.pathname)
+    var req_c = 0 // Request count for cache busting and easy identifying of request in traffic analyzer
+
+    /*
+     * Redirection with preflights
+     */
+
+    function redir_preflight(code) {
+        test(function() {
+            var client = new XMLHttpRequest(),
+                redir2 = crossdomain + 'resources/cors-makeheader.php?headers=x-test&' + req_c++
+
+            client.open('GET', crossdomain + 'resources/cors-makeheader.php?location='
+                               + encodeURIComponent(redir2) + '&' + req_c++,
+                        false)
+            client.setRequestHeader('x-test', 'test')
+            assert_throws('NETWORK_ERR', function() { client.send(null) });
+
+        },
+        'Redirect ' + code + ' on preflight')
+    }
+    redir_preflight(301)
+    redir_preflight(302)
+    redir_preflight(303)
+    redir_preflight(307)
+
+    function redir_after_preflight(code) {
+        test(function() {
+            var client = new XMLHttpRequest(),
+                redir2 = crossdomain + 'resources/cors-makeheader.php?headers=x-test&' + req_c++
+
+            client.open('GET', crossdomain + 'resources/cors-makeheader.php?'
+                               + 'preflight_safe&headers=x-test&location='
+                               + encodeURIComponent(redir2) + '&' + req_c++,
+                        false)
+            client.setRequestHeader('x-test', 'test')
+            assert_throws('NETWORK_ERR', function() { client.send(null) });
+
+        },
+        'Redirect ' + code + ' after preflight')
+    }
+    redir_after_preflight(301)
+    redir_after_preflight(302)
+    redir_after_preflight(303)
+    redir_after_preflight(307)
+
+    </script>
+ </body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/cors/submitted/opera/js/redirect.htm	Thu Dec 15 18:49:07 2011 +0100
@@ -0,0 +1,185 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>XMLHttpRequest: CORS - redirect</title>
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+  </head>
+  <body>
+    <p>This shouldn't be tested inside a tunnel.</p>
+    <div id="log"></div>
+    <script>
+
+    function dirname(path) {
+        return path.replace(/\/[^\/]*$/, '/')
+    }
+
+    var crossdomain = "http://crosssite." + location.hostname + dirname(location.pathname)
+    var req_c = 0 // Request count for cache busting and easy identifying of request in traffic analyzer
+
+    /*
+     * Redirection
+     */
+
+    test(function() {
+        var client = new XMLHttpRequest()
+        client.open('GET', 'resources/cors-makeheader.php?origin=none&location='
+                            + crossdomain + 'resources/cors-headers.php&' + req_c++,
+                    false)
+        client.send(null)
+
+        assert_equals(client.response, 'TEST')
+    },
+    'Local redirect to remote resource')
+
+    test(function() {
+        var client = new XMLHttpRequest()
+        client.open('GET', crossdomain + 'resources/cors-makeheader.php?origin=none&location='
+                           + dirname(location.href) + 'resources/cors-headers.php&' + req_c++,
+                    false)
+        assert_throws('NETWORK_ERR', function () { client.send(null) } )
+    },
+    'Remote redirect without Allow-Origin')
+
+    test(function() {
+        var client = new XMLHttpRequest()
+        client.open('GET', crossdomain + 'resources/cors-makeheader.php?origin=*&location='
+                           + dirname(location.href) + 'resources/cors-headers.php&' + req_c++,
+                    false)
+        client.send(null)
+
+        assert_equals(client.response, 'TEST')
+    },
+    'Remote redirect with Allow-Origin * to local resource')
+
+    test(function() {
+        var client = new XMLHttpRequest()
+        client.open('GET', crossdomain + 'resources/cors-makeheader.php?origin=&location='
+                           + dirname(location.href) + 'resources/cors-headers.php&' + req_c++,
+                    false)
+        assert_throws('NETWORK_ERR', function () { client.send(null) } )
+    },
+    'Remote redirect with empty Allow-Origin to local resource')
+
+    test(function() {
+        var client = new XMLHttpRequest()
+        client.open('GET', crossdomain + 'resources/cors-makeheader.php?origin='
+                           + location.protocol + "//" + location.host+'&location='
+                           + dirname(location.href) + 'resources/cors-headers.php&' + req_c++,
+                    false)
+        client.send(null)
+
+        assert_equals(client.response, 'TEST')
+    },
+    'Remote redirect with Allow-Origin http://' + location.host +' to local resource')
+
+    test(function() {
+        var client = new XMLHttpRequest()
+        client.open('GET', crossdomain + 'resources/cors-makeheader.php?origin='
+                           + location.protocol + "//" + location.host + '&location='
+                           + crossdomain + 'resources/cors-headers.php&' + req_c++,
+                    false)
+        client.send(null)
+
+        assert_equals(client.response, 'TEST')
+    },
+    'Remote redirect with Allow-Origin http://'
+        + location.host + ' to remote resource')
+
+    test(function() {
+        var client = new XMLHttpRequest(),
+            redir3 = dirname(location.href)
+                    + "resources/cors-makeheader.php?origin=none&get_value=NyanNyan&" + req_c++,
+            redir2 = crossdomain + 'resources/cors-makeheader.php?origin=*&location='
+                     + encodeURIComponent(redir3) + "&" + req_c++
+        client.open('GET', crossdomain + 'resources/cors-makeheader.php?origin='
+                           + location.protocol + "//" + location.host + '&location='
+                           + encodeURIComponent(redir2) + '&' + req_c++,
+                    false)
+        client.send(null)
+
+        r = JSON.parse(client.response)
+        assert_equals(r['get_value'], 'NyanNyan', 'Should meow')
+    },
+    'Remote redirect with Allow-Origin to remote redirect with Allow-Origin * to local resource')
+
+    test(function() {
+        var client = new XMLHttpRequest(),
+            redir3 = dirname(location.href)
+                    + "resources/cors-makeheader.php?origin=http://example.net&get_value=Cool&" + req_c++,
+            redir2 = crossdomain + 'resources/cors-makeheader.php?location='
+                     + encodeURIComponent(redir3) + '&' + req_c++
+        client.open('GET', crossdomain + 'resources/cors-makeheader.php?origin=*'
+                           + '&location=' + encodeURIComponent(redir2) + '&' + req_c++,
+                    false)
+        client.send(null)
+
+        r = JSON.parse(client.response)
+        assert_equals(r['get_value'], 'Cool')
+    },
+    'Remote redirect with Allow-Origin * to remote redirect with Allow-Origin to local resource with Allow-Origin example.net')
+
+    test(function() {
+        var client = new XMLHttpRequest(),
+            redir2 = dirname(location.href) + 'resources/cors-makeheader.php?origin=none&location='
+                     + crossdomain + 'resources/cors-makeheader.php&' + req_c++
+        client.open('GET', crossdomain + 'resources/cors-makeheader.php?location='
+                           + encodeURIComponent(redir2) + '&' + req_c++,
+                    false)
+        client.send(null)
+
+        r = JSON.parse(client.response)
+        assert_equals(r['origin'], location.protocol + "//" + location.host)
+    },
+    'Remote redirect with Allow-Origin to local redirect without Allow-Origin to remote resource with Allow_origin')
+
+    test(function() {
+        var client = new XMLHttpRequest(),
+            redir2 = crossdomain + 'resources/cors-makeheader.php?origin=none&' + req_c++
+
+        client.open('GET', crossdomain + 'resources/cors-makeheader.php?origin='
+                           + location.protocol + "//" + location.host + '&location='
+                           + encodeURIComponent(redir2) + '&' + req_c++,
+                    false)
+        assert_throws('NETWORK_ERR', function () { client.send(null) } )
+    },
+    'Remote redirect with Allow-Origin to remote resource without Allow-Origin')
+
+    test(function() {
+        var client = new XMLHttpRequest(),
+            redir2 = crossdomain + 'resources/cors-makeheader.php?origin=null&' + req_c++
+
+        client.open('GET', crossdomain + 'resources/cors-makeheader.php?origin='
+                           + location.protocol + "//" + location.host + '&location='
+                           + encodeURIComponent(redir2) + '&' + req_c++,
+                    false)
+        assert_throws('NETWORK_ERR', function () { client.send(null) } )
+    },
+    'Remote redirect with Allow-Origin to remote resource with Allow-Origin null')
+
+    function redir(code) {
+        test(function() {
+            var client = new XMLHttpRequest(),
+                redir3 = crossdomain + 'resources/cors-makeheader.php?code=' + code + '&' + req_c++,
+                redir2 = crossdomain + 'resources/cors-makeheader.php?code=' + code
+                         + '&location=' + encodeURIComponent(redir3) + '&' + req_c++
+
+            client.open('GET', crossdomain + 'resources/cors-makeheader.php?location='
+                               + encodeURIComponent(redir2) + '&' + req_c++,
+                        false)
+            client.send(null)
+
+            r = JSON.parse(client.response)
+            assert_equals(r['origin'], location.protocol + "//" + location.host)
+        },
+        'Redirect ' + code)
+    }
+
+    redir(301);
+    redir(302);
+    redir(303);
+    redir(307);
+
+    </script>
+ </body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/cors/submitted/opera/js/request.htm	Thu Dec 15 18:49:07 2011 +0100
@@ -0,0 +1,84 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>XMLHttpRequest: CORS - request</title>
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+  </head>
+  <body>
+    <p>This shouldn't be tested inside a tunnel.</p>
+    <div id="log"></div>
+    <script>
+
+    var crossdomain = "http://crosssite." + location.host + location.pathname.replace(/\/[^\/]*$/, '/')
+
+
+    /*
+     * Request Headers
+     */
+
+    test(function() {
+        var client = new XMLHttpRequest()
+        client.open('GET', crossdomain + 'resources/cors-makeheader.php?headers=x-print', false)
+        client.setRequestHeader('x-print', 'unicorn')
+        client.send(null)
+
+        res = JSON.parse(client.response)
+        assert_equals(res['x-print'], 'unicorn')
+    }, 'basic request header')
+
+    test(function() {
+        var client = new XMLHttpRequest()
+        client.open('GET', crossdomain + 'resources/cors-makeheader.php?headers=x-print,', false)
+        client.setRequestHeader('x-print', 'unicorn')
+        client.setRequestHeader('content-type', 'text/plain')
+        client.setRequestHeader('accept', 'test')
+        client.setRequestHeader('accept-language', 'nn')
+        client.setRequestHeader('content-language', 'nn')
+        client.send(null)
+
+        res = JSON.parse(client.response)
+        assert_equals(res['x-print'], 'unicorn')
+        assert_equals(res['content-type'], 'text/plain')
+        assert_equals(res['accept'], 'test')
+        assert_equals(res['accept-language'], 'nn')
+        assert_equals(res['content-language'], 'nn')
+    }, 'simple request headers need not be in allow-headers')
+
+    test(function() {
+        var client = new XMLHttpRequest()
+        client.open('GET', crossdomain + 'resources/cors-makeheader.php?headers=x-print', false)
+        client.setRequestHeader('x-print', 'unicorn')
+        client.setRequestHeader('y-print', 'unicorn')
+        assert_throws('NETWORK_ERR', function() { client.send(null) })
+    }, 'NETWORK_ERR on disallowed request header')
+
+    test(function() {
+        var client = new XMLHttpRequest()
+        client.open('GET', crossdomain + 'resources/cors-makeheader.php?headers=,y-lol,x-PriNT,%20,,,Y-PRINT', false)
+        client.setRequestHeader('x-print', 'unicorn')
+        client.setRequestHeader('y-print', 'narwhal')
+        client.send(null)
+
+        res = JSON.parse(client.response)
+        assert_equals(res['x-print'], 'unicorn')
+        assert_equals(res['y-print'], 'narwhal')
+    }, 'Strange allowheaders')
+
+    test(function() {
+        var client = new XMLHttpRequest()
+        assert_throws('INVALID_STATE_ERR', function() { client.setRequestHeader('x-print', 'unicorn') })
+    },
+    'INVALID_STATE_ERR on setRequestHeader before open()')
+
+    test(function() {
+        var client = new XMLHttpRequest()
+        client.open('GET', crossdomain + 'resources/cors-makeheader.php?headers=,y-lol,x-PriNT,%20,,,Y-PRINT', false)
+        client.send()
+        assert_throws('INVALID_STATE_ERR', function() { client.setRequestHeader('x-print', 'unicorn') })
+    },
+    'INVALID_STATE_ERR on setRequestHeader after send()')
+
+    </script>
+ </body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/cors/submitted/opera/js/resources/.hgignore	Thu Dec 15 18:49:07 2011 +0100
@@ -0,0 +1,1 @@
+logs.txt
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/cors/submitted/opera/js/resources/checkandremovefromlog.php	Thu Dec 15 18:49:07 2011 +0100
@@ -0,0 +1,34 @@
+<?php
+  $file_name = 'logs.txt';
+  $ident = isset($_GET['ident']) ? $_GET['ident'] : NULL;
+  $buffer = '';
+  $obj;
+
+  $file = fopen($file_name,'r+');
+
+  if (filesize($file_name))
+  {
+    $buffer = fread($file, filesize($file_name));
+
+    if ($buffer)
+      $obj = json_decode($buffer);
+  }
+
+  if (isset($ident))
+    if ($obj->$ident)
+    {
+      print "1";
+
+      unset($obj->$ident);
+
+      $buffer = json_encode($obj);
+
+      rewind($file);
+      ftruncate($file, 0);
+      fwrite($file, $buffer);
+    }
+    else
+      print "0";
+
+  fclose($file);
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/cors/submitted/opera/js/resources/cors-cookie.php	Thu Dec 15 18:49:07 2011 +0100
@@ -0,0 +1,21 @@
+<?php
+ $origin = isset($_GET['origin']) ? $_GET['origin'] : $_SERVER['HTTP_ORIGIN'];
+ $credentials = isset($_GET['credentials']) ? $_GET['credentials'] : 'true';
+
+ header("Content-Type: text/plain");
+ if ($origin != 'none')
+   header("Access-Control-Allow-Origin: {$origin}");
+ if ($credentials != 'none')
+   header("Access-Control-Allow-Credentials: {$credentials}");
+
+ $ident = isset($_GET['ident']) ? $_GET['ident'] : 'test';
+
+ if (isset($_COOKIE[$ident])) {
+   /* Delete the cookie */
+   header("Set-Cookie: $ident=COOKIE; expires=Fri, 27 Jul 2001 02:47:11 UTC");
+   echo $_COOKIE[$ident];
+ }
+ else {
+   header("Set-Cookie: $ident=COOKIE");
+   echo 'NO_COOKIE';
+ }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/cors/submitted/opera/js/resources/cors-headers.php	Thu Dec 15 18:49:07 2011 +0100
@@ -0,0 +1,28 @@
+<?php
+ header("Access-Control-Allow-Origin: *");
+ header("Access-Control-Expose-Headers: X-Custom-Header, X-Custom-Header-Empty, X-Custom-Header-Comma, X-Custom-Header-Bytes");
+ header("Access-Control-Expose-Headers: X-Second-Expose", false);
+ header("Access-Control-Expose-Headers: Date", false);
+
+ header("Content-Type: text/plain");
+
+ header("X-Custom-Header: test");
+ header("X-Custom-Header: test");
+ header("Set-Cookie: test1=t1;max-age=2");
+ header("Set-Cookie2: test2=t2;Max-Age=2");
+ header("X-Custom-Header-Empty:");
+ header("X-Custom-Header-Comma: 1");
+ header("X-Custom-Header-Comma: 2", false);
+ header("X-Custom-Header-Bytes: …");
+ header("X-Nonexposed: unicorn");
+ header("X-Second-Expose: flyingpig");
+
+ /* Simple response headers */
+ header("Cache-Control: no-cache");
+ header("Content-Language: nn");
+ header("Expires: Thu, 01 Dec 1994 16:00:00 GMT");
+ header("Last-Modified: Thu, 01 Dec 1994 10:00:00 GMT");
+ header("Pragma: no-cache");
+
+ echo "TEST";
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/cors/submitted/opera/js/resources/cors-makeheader.php	Thu Dec 15 18:49:07 2011 +0100
@@ -0,0 +1,39 @@
+<?php
+
+$origin = isset($_GET['origin']) ? $_GET['origin'] : $_SERVER['HTTP_ORIGIN'];
+
+if ($origin != 'none')
+    header("Access-Control-Allow-Origin: $origin");
+
+/* Preflight */
+if (isset($_GET['headers']))
+    header("Access-Control-Allow-Headers: {$_GET['headers']}");
+if (isset($_GET['credentials']))
+    header("Access-Control-Allow-Credentials: {$_GET['credentials']}");
+if (isset($_GET['methods']))
+    header("Access-Control-Allow-Methods: {$_GET['methods']}");
+
+if (isset($_GET['location'])
+    && !(isset($_GET['preflight_safe'])
+        && $_SERVER['REQUEST_METHOD'] == 'OPTIONS'))
+{
+    $code = ctype_digit($_GET["code"]) ? $_GET["code"] : "302";
+    header("Location: {$_GET['location']}", true, $code);
+}
+
+foreach ($_SERVER as $name => $value)
+{
+    if (substr($name, 0, 5) == 'HTTP_')
+    {
+        $name = strtolower(str_replace('_', '-', substr($name, 5)));
+        $headers[$name] = $value;
+    } else if ($name == "CONTENT_TYPE") {
+        $headers["content-type"] = $value;
+    } else if ($name == "CONTENT_LENGTH") {
+        $headers["content-length"] = $value;
+    }
+}
+
+$headers['get_value'] = $_GET['get_value'];
+
+echo json_encode( $headers );
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/cors/submitted/opera/js/resources/log.php	Thu Dec 15 18:49:07 2011 +0100
@@ -0,0 +1,27 @@
+<?php
+  $file_name = 'logs.txt';
+  $ident = isset($_GET['ident']) ? $_GET['ident'] : NULL;
+  $buffer = '';
+  $obj;
+
+  $file = fopen($file_name, 'c+');
+
+  if (filesize($file_name))
+  {
+    $buffer = fread($file, filesize($file_name));
+
+    if ($buffer)
+      $obj = json_decode($buffer);
+  }
+
+  if (isset($ident))
+    if (!$obj->$ident)
+      $obj->$ident = true;
+
+  $buffer = json_encode($obj);
+
+  rewind($file);
+  ftruncate($file, 0);
+  fwrite($file, $buffer);
+  fclose($file);
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/cors/submitted/opera/js/resources/preflight.php	Thu Dec 15 18:49:07 2011 +0100
@@ -0,0 +1,20 @@
+<?php
+header("Content-Type: text/plain");
+
+if($_SERVER['REQUEST_METHOD'] == 'OPTIONS')
+{
+    if(!isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD']))
+	die("ERROR: No access-control-request-method in preflight!");
+
+    header("Access-Control-Allow-Headers: x-print, " .
+            "{$_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']}");
+
+    if (isset($_GET['max_age']))
+        header("Access-Control-Max-Age: {$_GET['max_age']}");
+
+    include("log.php");
+}
+header("Access-Control-Allow-Origin: *");
+
+$p = isset($_SERVER['HTTP_X_PRINT']) ? $_SERVER['HTTP_X_PRINT'] : "NO";
+echo $p;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/cors/submitted/opera/js/resources/status.php	Thu Dec 15 18:49:07 2011 +0100
@@ -0,0 +1,40 @@
+<?php
+
+  header("Access-Control-Allow-Origin: {$_SERVER['HTTP_ORIGIN']}");
+  header("Access-Control-Expose-Headers: X-Request-Method");
+  if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS')
+    header("Access-Control-Allow-Methods: GET, CHICKEN, HEAD, POST, PUT");
+  if (isset($_GET['headers']))
+    header("Access-Control-Allow-Headers: {$_GET['headers']}");
+  header("X-Request-Method: " .
+    (isset($_SERVER["REQUEST_METHOD"]) ? $_SERVER["REQUEST_METHOD"] : ""));
+  header("X-A-C-Request-Method: " .
+    (isset($_SERVER["HTTP_ACCESS_CONTROL_REQUEST_METHOD"])
+      ? $_SERVER["HTTP_ACCESS_CONTROL_REQUEST_METHOD"] : ""));
+
+  // Hack for PHP
+  function stripslashes_recursive($var) {
+    foreach($var as $i => $value)
+      $var[$i] = stripslashes($value);
+    return $var;
+  }
+  if(get_magic_quotes_gpc()) {
+    $_GET = stripslashes_recursive($_GET);
+  }
+
+  // This should reasonably work for most response codes.
+  $code = isset($_GET['code']) && ctype_digit($_GET["code"]) ? $_GET["code"] : "200";
+  $text = isset($_GET["text"]) ? $_GET["text"] : "OMG";
+
+  if (isset($_GET['preflight'])
+      && ctype_digit($_GET['preflight'])
+      && $_SERVER['REQUEST_METHOD'] == 'OPTIONS')
+    $code = $_GET['preflight'];
+
+  header("HTTP/1.1 " . $code . " " . $text);
+
+  if (isset($_GET['type']))
+    header("Content-Type:" . $_GET['type']);
+  if (isset($_GET["content"]))
+    echo $_GET['content'];
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/cors/submitted/opera/js/response.htm	Thu Dec 15 18:49:07 2011 +0100
@@ -0,0 +1,112 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>XMLHttpRequest: CORS - Response headers</title>
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+  </head>
+  <body>
+    <p>This shouldn't be tested inside a tunnel.</p>
+    <div id="log"></div>
+    <script>
+
+    var crossdomain = "http://crosssite." + location.host + location.pathname.replace(/\/[^\/]*$/, '/')
+
+    /*
+     * Response Headers
+     */
+
+    function check_response_header(head, value, desc) {
+        test(function() {
+            var client = new XMLHttpRequest()
+            client.open('GET', crossdomain + 'resources/cors-headers.php', false)
+            client.send(null)
+
+            if (typeof value === 'function')
+                value(client, head)
+            else
+                assert_equals(client.getResponseHeader(head), value, head)
+        },
+        desc)
+    }
+    check_response_header('X-Custom-Header-Comma', '1, 2', 'getResponseHeader: Expose Access-Control-Expose-Headers (x-custom-header-comma)')
+    check_response_header('X-Second-Expose', 'flyingpig', 'getResponseHeader: Expose second Access-Control-Expose-Headers (x-second-expose)')
+    check_response_header(' x-custom-header', null, 'getResponseHeader: Don\'t trim whitespace')
+    check_response_header('x-custom-header-bytes', "\xE2\x80\xA6", 'getResponseHeader: x-custom-header bytes')
+    check_response_header('Date',
+        function(client, head) { assert_true(client.getResponseHeader(head).length > 2) },
+        'getResponseHeader: Exposed server field readable (Date)')
+
+    function default_readable(head, value) {
+        check_response_header(head, value, 'getResponseHeader: '+head+': readable by default')
+    }
+    default_readable("Cache-Control", "no-cache");
+    default_readable("Content-Language", "nn");
+    default_readable("Expires", "Thu, 01 Dec 1994 16:00:00 GMT");
+    default_readable("Last-Modified", "Thu, 01 Dec 1994 10:00:00 GMT");
+    default_readable("Pragma", "no-cache");
+
+
+    function default_unreadable(head) {
+        check_response_header(head, null, 'getResponseHeader: '+head+': unreadable by default')
+    }
+    default_unreadable("Server")
+    default_unreadable("X-Powered-By")
+
+
+    ;(function ()
+    { /* Don't pollute with variable "test" */
+        var test = async_test("getResponseHeader: Combined testing of cors response headers")
+        test.step(function()
+        {
+            var client = new XMLHttpRequest();
+            client.open("GET", crossdomain + 'resources/cors-headers.php')
+            window.c=client;
+            client.onreadystatechange = function()
+            {
+                test.step(function()
+                {
+                    if(client.readyState == 1)
+                    {
+                        assert_equals(client.getResponseHeader("x-custom-header"), null, 'x-custom-header')
+                    }
+                    if(client.readyState > 1)
+                    {
+                        assert_equals(client.getResponseHeader("x-custom-header"), "test", 'x-custom-header')
+                        assert_equals(client.getResponseHeader("x-custom-header-empty"), "", 'x-custom-header-empty')
+                        assert_equals(client.getResponseHeader("set-cookie"), null)
+                        assert_equals(client.getResponseHeader("set-cookie2"), null)
+                        assert_equals(client.getResponseHeader("x-non-existent-header"), null)
+                        assert_equals(client.getResponseHeader("x-nonexposed"), null)
+                    }
+                    if(client.readyState == 4)
+                    {
+                        test.done()
+                    }
+                })
+            }
+            client.send(null)
+        })
+    })();
+
+    test(function() {
+        var client = new XMLHttpRequest()
+        client.open('GET', crossdomain + 'resources/cors-headers.php', false)
+        client.send(null)
+        assert_equals(client.getResponseHeader("x-custom-header"), "test", 'x-custom-header')
+        assert_equals(client.getResponseHeader("x-nonexposed"), null, 'x-nonexposed')
+    }, 'getResponse: don\'t expose x-nonexposed')
+
+    test(function() {
+        var client = new XMLHttpRequest()
+        client.open('GET', crossdomain + 'resources/cors-headers.php', false)
+        client.send(null)
+
+        h = client.getAllResponseHeaders().toLowerCase()
+        assert_true( h.indexOf('x-custom-header') >= 0, 'x-custom-header present')
+        assert_true( h.indexOf('x-nonexposed') === -1, 'x-nonexposed not present')
+    }, 'getAllResponseHeaders: don\'t expose x-nonexposed')
+
+    </script>
+ </body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/cors/submitted/opera/js/simple-requests.htm	Thu Dec 15 18:49:07 2011 +0100
@@ -0,0 +1,95 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>XMLHttpRequest: CORS - simple requests</title>
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+  </head>
+  <body>
+    <p>This shouldn't be tested inside a tunnel.</p>
+    <div id="log"></div>
+    <script>
+
+    var crossdomain = "http://crosssite." + location.host + location.pathname.replace(/\/[^\/]*$/, '/')
+
+    /*
+     * Simple requests that shouldn't trigger preflight
+     */
+
+    var test_c = 0;
+
+    function check_simple(method, headers)
+    {
+        test(function() {
+            var time = new Date().getTime(),
+                client = new XMLHttpRequest()
+            test_c++
+            client.open(method, crossdomain + 'resources/preflight.php?ident='
+                                + test_c + time, false)
+            for (head in headers)
+                client.setRequestHeader(head, headers[head])
+            client.send("data")
+            assert_equals(client.getResponseHeader('content-type'), "text/plain")
+            if (method == 'HEAD')
+                assert_equals(client.response, '', 'response')
+            else
+                assert_equals(client.response, 'NO', 'response')
+
+            client.open('GET', 'resources/checkandremovefromlog.php?ident='
+                              + test_c + time, false)
+            client.send("data")
+            assert_equals(client.response, "0", "Found preflight log")
+        },
+        'no preflight on ' + method + ' and request headers ' + JSON.stringify(headers))
+    }
+
+    function check_simple_headers(headers) {
+        check_simple('GET', headers)
+        check_simple('HEAD', headers)
+        check_simple('POST', headers)
+    }
+
+    check_simple_headers({'Accept': 'test'})
+    check_simple_headers({'accept-language': 'test'})
+    check_simple_headers({'CONTENT-language': 'test'})
+
+    check_simple_headers({'Content-Type': 'application/x-www-form-urlencoded'})
+    check_simple_headers({'content-type': 'multipart/form-data'})
+    check_simple_headers({'content-type': 'text/plain'})
+
+    check_simple_headers({
+                            'accept': 'test',
+                            'accept-language': 'test',
+                            'content-language': 'test',
+                            'content-type': 'text/plain; parameter=whatever'
+                         })
+
+    check_simple('Get', {'content-type': 'text/plain; parameter=extra_bonus'})
+    check_simple('post', {'content-type': 'text/plain'})
+
+
+    /* Extra async test */
+
+    var simple_async = async_test("Check simple headers (async)")
+    simple_async.step(function (){
+        var time = new Date().getTime(),
+            client = new XMLHttpRequest()
+        client.open('POST', crossdomain + 'resources/preflight.php?ident='
+                            + time, true)
+
+        client.setRequestHeader('Accept', 'jewelry')
+        client.setRequestHeader('accept-language', 'nn_NO,nn,en')
+        client.setRequestHeader('content-type', 'text/plain; parameter=extra')
+        client.setRequestHeader('content-Language', 'nn_NO')
+
+        client.onload = simple_async.step_func(function() {
+            assert_equals(client.getResponseHeader('content-type'), "text/plain", 'content-type response header')
+            assert_equals(client.response, 'NO', 'response')
+            simple_async.done()
+        })
+        client.onerror = simple_async.step_func(function () { assert_unreached('onerror') })
+        client.send()
+    })
+    </script>
+ </body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/cors/submitted/opera/js/status-async.htm	Thu Dec 15 18:49:07 2011 +0100
@@ -0,0 +1,93 @@
+<!doctype html>
+<html>
+  <head>
+    <title>XMLHttpRequest: CORS - status (async)</title>
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+  </head>
+  <body>
+    <p>This shouldn't be tested inside a tunnel.</p>
+    <div id="log"></div>
+    <script>
+      var crossdomain = "http://crosssite." + location.hostname + location.pathname.replace(/\/[^\/]*$/, '/')
+
+      function statusRequest(method, code, text, content, type) {
+        var test = async_test(document.title + " ("
+          + method + " " + code + ")")
+        test.step(function() {
+          var client = new XMLHttpRequest()
+          client.open(method, crossdomain + "resources/status.php?code="
+            + code + "&text=" + text + "&content=" + content + "&type=" + type, true)
+          client.onreadystatechange = test.step_func(function() {
+            if (client.readyState != client.DONE)
+              return
+            assert_equals(client.status, code, 'response status')
+            assert_equals(client.statusText, text, 'response status text')
+            assert_equals(client.getResponseHeader("X-Request-Method"), method, 'method')
+            if(method != "HEAD") {
+              if(type == "text/xml") {
+                assert_equals(client.responseXML.documentElement.localName, "x", 'responseXML')
+              }
+              assert_equals(client.response, content, 'response content')
+            }
+            test.done()
+          })
+          client.send(null)
+        })
+      }
+
+      /*            method     code text  content        type */
+      statusRequest("GET",     200, 'OK', 'Not today.',  '')
+      statusRequest("POST",    200, 'OK', '<x>402<\/x>', 'text/xml')
+      statusRequest("HEAD",    200, 'OK', 'Nice!',       'text/doesnotmatter')
+      statusRequest("PUT",     200, 'OK', '400',         'text/plain')
+      statusRequest("CHICKEN", 200, 'OK', 'bah',         '')
+
+
+      function statusRequestFail(method, code, expect_code, nonsimple) {
+        var test = async_test(document.title + " ("
+            + method + " " + code + ") should fail" + ((nonsimple===true)?' (nonsimple)':''))
+        if (expect_code === undefined)
+          expect_code = code
+
+        test.step(function() {
+          var client = new XMLHttpRequest()
+
+          client.open(method, crossdomain + "resources/status.php?code="
+            + code + '&headers=x-nonsimple', true)
+
+          if (nonsimple === true)
+            client.setRequestHeader('x-nonsimple', true)
+
+          client.onreadystatechange = test.step_func(function() {
+            assert_equals(client.response, "", "response data")
+            assert_equals(client.status, expect_code, "response status")
+            if (client.readyState == client.DONE)
+              test.done()
+          })
+
+          client.send()
+        })
+      }
+
+      /*                                 expect
+                        method     code  status */
+      statusRequestFail("GET",     204)
+      statusRequestFail("HEAD",    401)
+      statusRequestFail("POST",    404)
+
+      /* Preflight response status is not 200, so the algorithm set status to 0. */
+      statusRequestFail("PUT",     699,  0)
+      statusRequestFail("CHICKEN", 501,  0)
+
+      /*                                    "forced"
+                                            preflight */
+      statusRequestFail("GET",     204,  0, true)
+      statusRequestFail("HEAD",    401,  0, true)
+      statusRequestFail("POST",    404,  0, true)
+      statusRequestFail("PUT",     699,  0, true)
+      statusRequestFail("CHICKEN", 501,  0, true)
+
+    </script>
+  </body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/cors/submitted/opera/js/status-basic.htm	Thu Dec 15 18:49:07 2011 +0100
@@ -0,0 +1,66 @@
+<!doctype html>
+<html>
+  <head>
+    <title>XMLHttpRequest: CORS status/statusText - various responses (async)</title>
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+  </head>
+  <body>
+    <p>This shouldn't be tested inside a tunnel.</p>
+    <div id="log"></div>
+    <script>
+      var crossdomain = "http://crosssite." + location.hostname + location.pathname.replace(/\/[^\/]*$/, '/')
+
+      function statusRequest(method, code, text, content, type) {
+        test(function() {
+          var client = new XMLHttpRequest()
+          client.open(method, crossdomain + "resources/status.php?code=" + code + "&text=" + text + "&content=" + content + "&type=" + type, false)
+          client.setRequestHeader('Content-Type', 'text/plain')
+          client.send(null)
+          assert_equals(client.status, code)
+          assert_equals(client.statusText, text)
+          assert_equals(client.getResponseHeader("X-Request-Method"), method)
+          if(method != "HEAD") {
+            if(type == "text/xml") {
+              assert_equals(client.responseXML.documentElement.localName, "x")
+            }
+            assert_equals(client.responseText, content)
+          }
+        }, document.title + " (" + method + " " + code + ")")
+      }
+
+      statusRequest("GET", 200, 'OK', 'Not today.', '')
+      statusRequest("PUT", 200, 'OK', '<x>402<\/x>', 'text/xml')
+      statusRequest("HEAD", 200, 'OK', 'Nice!', 'text/doesnotmatter')
+      statusRequest("POST", 200, 'OK', '400', 'text/plain')
+      statusRequest("CHICKEN", 200, 'OK', 'bah', '')
+
+
+      function statusRequestFail(method, code, text) {
+        test(function() {
+          var client = new XMLHttpRequest()
+          client.open(method, crossdomain + "resources/status.php?code="
+            + code + "&text=" + text, false)
+          assert_throws('NETWORK_ERR', function() { client.send(null) })
+        }, document.title + " (" + method + " " + code + ") throws NETWORK_ERR")
+      }
+      function status(code, text) {
+        statusRequestFail("GET", code, text)
+        statusRequestFail("HEAD", code, text)
+        statusRequestFail("POST", code, text)
+        statusRequestFail("PUT", code, text)
+        statusRequestFail("CHICKEN", code, text)
+      }
+
+      status(201, "UNICORNSWAM")
+      status(204, "UNICORNSWIN")
+      status(401, "OH HELLO")
+      status(402, "FIVE BUCKS")
+      status(402, "FREE")
+      status(404, "404 NOT FOUND")
+      status(502, "lowercase")
+      status(503, "HOUSTON WE HAVE A")
+      status(699, "WAY OUTTA RANGE")
+    </script>
+  </body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/cors/submitted/opera/js/status-preflight.htm	Thu Dec 15 18:49:07 2011 +0100
@@ -0,0 +1,44 @@
+<!doctype html>
+<html>
+  <head>
+    <title>CORS - status after preflight</title>
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+  </head>
+  <body>
+    <p>This shouldn't be tested inside a tunnel.</p>
+    <div id="log"></div>
+    <script>
+      var crossdomain = "http://crosssite." + location.hostname + location.pathname.replace(/\/[^\/]*$/, '/')
+
+      function statusAfterPreflight(method, code) {
+        var test = async_test(document.title + " on "
+            + method + " " + code)
+
+        test.step(function() {
+          var client = new XMLHttpRequest()
+          client.open(method, crossdomain + "resources/status.php?code="
+            + code + '&headers=x-nonsimple&preflight=200', true)
+
+          client.setRequestHeader('x-nonsimple', true)
+          client.onreadystatechange = test.step_func(function() {
+            assert_equals(client.response, "", "response data")
+            assert_equals(client.status, code, "response status")
+          })
+          client.onerror = test.step_func(function() {
+            test.done()
+          })
+          client.send()
+        })
+      }
+
+      /*                   method     code */
+      statusAfterPreflight("GET",     204)
+      statusAfterPreflight("HEAD",    401)
+      statusAfterPreflight("POST",    404)
+      statusAfterPreflight("PUT",     699)
+      statusAfterPreflight("CHICKEN", 501)
+
+    </script>
+  </body>
+</html>