Safari warns that it needs to resend the form in an iFrame when going back
authorjonlee@apple.com <jonlee@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 9 May 2012 00:57:03 +0000 (00:57 +0000)
committerjonlee@apple.com <jonlee@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 9 May 2012 00:57:03 +0000 (00:57 +0000)
https://bugs.webkit.org/show_bug.cgi?id=82658
<rdar://problem/11292558>

Reviewed by Darin Adler.

Source/WebCore:

Test: http/tests/loading/post-in-iframe-with-back-navigation.html

* WebCore.exp.in: Add _wkCFURLRequestAllowAllPostCaching.
* platform/mac/WebCoreSystemInterface.h: Add wkCFURLRequestAllowAllPostCaching.
* platform/mac/WebCoreSystemInterface.mm: Add wkCFURLRequestAllowAllPostCaching.
* platform/network/cf/ResourceRequestCFNet.cpp:
(WebCore::ResourceRequest::doUpdatePlatformRequest): Set the bit to cache all POST responses.
* platform/network/mac/ResourceRequestMac.mm:
(WebCore::ResourceRequest::doUpdatePlatformRequest): Set the bit to cache all POST responses.

Source/WebKit/mac:

* WebCoreSupport/WebSystemInterface.mm:
(InitWebCoreSystemInterface): Add wkCFURLRequestAllowAllPostCaching.

Source/WebKit2:

* WebProcess/WebCoreSupport/mac/WebSystemInterface.mm:
(InitWebCoreSystemInterface): Add wkCFURLRequestAllowAllPostCaching.

WebKitLibraries:

* WebKitSystemInterface.h:
* libWebKitSystemInterfaceLeopard.a:
* libWebKitSystemInterfaceLion.a:
* libWebKitSystemInterfaceSnowLeopard.a:

LayoutTests:

Add new test which navigates a series of pages in an iframe. Each navigation is a POST.
At the third page we click on a back link, and expect to see stale POST data.

* http/tests/loading/post-in-iframe-with-back-navigation-expected.txt: Added.
* http/tests/loading/post-in-iframe-with-back-navigation.html: Added.
* http/tests/loading/resources/post-in-iframe-with-back-navigation-page-1.php: Added.
* http/tests/loading/resources/post-in-iframe-with-back-navigation-page-2.php: Added.
* http/tests/loading/resources/post-in-iframe-with-back-navigation-page-3.php: Added.
* http/tests/resources/js-test-post.js: Added. Copied from fast/js/resources since it is
inaccessible to the test server.
* http/tests/resources/js-test-pre.js: Added. Copied from fast/js/resources since it is
inaccessible to the test server.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@116473 268f45cc-cd09-0410-ab3c-d52691b4dbfc

23 files changed:
LayoutTests/ChangeLog
LayoutTests/http/tests/loading/post-in-iframe-with-back-navigation-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/loading/post-in-iframe-with-back-navigation.html [new file with mode: 0644]
LayoutTests/http/tests/loading/resources/post-in-iframe-with-back-navigation-page-1.php [new file with mode: 0644]
LayoutTests/http/tests/loading/resources/post-in-iframe-with-back-navigation-page-2.php [new file with mode: 0644]
LayoutTests/http/tests/loading/resources/post-in-iframe-with-back-navigation-page-3.php [new file with mode: 0644]
LayoutTests/http/tests/resources/js-test-post.js [new file with mode: 0644]
LayoutTests/http/tests/resources/js-test-pre.js [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/WebCore.exp.in
Source/WebCore/platform/mac/WebCoreSystemInterface.h
Source/WebCore/platform/mac/WebCoreSystemInterface.mm
Source/WebCore/platform/network/cf/ResourceRequestCFNet.cpp
Source/WebCore/platform/network/mac/ResourceRequestMac.mm
Source/WebKit/mac/ChangeLog
Source/WebKit/mac/WebCoreSupport/WebSystemInterface.mm
Source/WebKit2/ChangeLog
Source/WebKit2/WebProcess/WebCoreSupport/mac/WebSystemInterface.mm
WebKitLibraries/ChangeLog
WebKitLibraries/WebKitSystemInterface.h
WebKitLibraries/libWebKitSystemInterfaceLeopard.a
WebKitLibraries/libWebKitSystemInterfaceLion.a
WebKitLibraries/libWebKitSystemInterfaceSnowLeopard.a

index f4e3df1..0876121 100644 (file)
@@ -1,3 +1,24 @@
+2012-05-08  Jon Lee  <jonlee@apple.com>
+
+        Safari warns that it needs to resend the form in an iFrame when going back
+        https://bugs.webkit.org/show_bug.cgi?id=82658
+        <rdar://problem/11292558>
+
+        Reviewed by Darin Adler.
+
+        Add new test which navigates a series of pages in an iframe. Each navigation is a POST.
+        At the third page we click on a back link, and expect to see stale POST data.
+
+        * http/tests/loading/post-in-iframe-with-back-navigation-expected.txt: Added.
+        * http/tests/loading/post-in-iframe-with-back-navigation.html: Added.
+        * http/tests/loading/resources/post-in-iframe-with-back-navigation-page-1.php: Added.
+        * http/tests/loading/resources/post-in-iframe-with-back-navigation-page-2.php: Added.
+        * http/tests/loading/resources/post-in-iframe-with-back-navigation-page-3.php: Added.
+        * http/tests/resources/js-test-post.js: Added. Copied from fast/js/resources since it is
+        inaccessible to the test server.
+        * http/tests/resources/js-test-pre.js: Added. Copied from fast/js/resources since it is
+        inaccessible to the test server.
+
 2012-05-08  Eric Seidel  <eric@webkit.org>
 
         Add stylesheet inheritance support to IFRAME_SEAMLESS
diff --git a/LayoutTests/http/tests/loading/post-in-iframe-with-back-navigation-expected.txt b/LayoutTests/http/tests/loading/post-in-iframe-with-back-navigation-expected.txt
new file mode 100644 (file)
index 0000000..02c3a2f
--- /dev/null
@@ -0,0 +1,44 @@
+main frame - didStartProvisionalLoadForFrame
+main frame - didCommitLoadForFrame
+main frame - didReceiveTitle: Resending form on back navigation from POST submissions
+frame "frame" - didStartProvisionalLoadForFrame
+frame "frame" - didCommitLoadForFrame
+frame "frame" - didFinishDocumentLoadForFrame
+frame "frame" - didHandleOnloadEventsForFrame
+frame "frame" - didFinishLoadForFrame
+main frame - didFinishDocumentLoadForFrame
+main frame - didHandleOnloadEventsForFrame
+main frame - didFinishLoadForFrame
+frame "frame" - willPerformClientRedirectToURL: http://127.0.0.1:8000/loading/resources/post-in-iframe-with-back-navigation-page-2.php 
+frame "frame" - didStartProvisionalLoadForFrame
+frame "frame" - didCancelClientRedirectForFrame
+frame "frame" - didCommitLoadForFrame
+frame "frame" - didFinishDocumentLoadForFrame
+frame "frame" - didHandleOnloadEventsForFrame
+frame "frame" - didFinishLoadForFrame
+frame "frame" - willPerformClientRedirectToURL: http://127.0.0.1:8000/loading/resources/post-in-iframe-with-back-navigation-page-3.php 
+frame "frame" - didStartProvisionalLoadForFrame
+frame "frame" - didCancelClientRedirectForFrame
+frame "frame" - didCommitLoadForFrame
+frame "frame" - didFinishDocumentLoadForFrame
+frame "frame" - didHandleOnloadEventsForFrame
+frame "frame" - didFinishLoadForFrame
+frame "frame" - didStartProvisionalLoadForFrame
+frame "frame" - didCommitLoadForFrame
+frame "frame" - didFinishDocumentLoadForFrame
+frame "frame" - didHandleOnloadEventsForFrame
+frame "frame" - didFinishLoadForFrame
+
+Resending form on back navigation from POST submissions
+
+To test manually, click on the navigation links in the iframe. When going back from page 3, it should navigate to page 2 without requesting to resend the form.
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+PASS getTitle() is "Page 1"
+PASS getTitle() is "Page 2"
+PASS getTitle() is "Page 3"
+PASS getTitle() is "Page 2"
+PASS window.frames[0].document.getElementById('submissionTime').innerText is step2output
+
diff --git a/LayoutTests/http/tests/loading/post-in-iframe-with-back-navigation.html b/LayoutTests/http/tests/loading/post-in-iframe-with-back-navigation.html
new file mode 100644 (file)
index 0000000..61ac693
--- /dev/null
@@ -0,0 +1,80 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <title>Resending form on back navigation from POST submissions</title>
+    <script src="../resources/js-test-pre.js"></script>
+</head>
+<body onload="runTest()">
+<iframe id="frame" onload="nextStep()" src="resources/post-in-iframe-with-back-navigation-page-1.php" width=300 height=300></iframe>
+<p>Resending form on back navigation from POST submissions<br/><br/>
+
+To test manually, click on the navigation links in the iframe. When going back from page 3, it should navigate to page 2 without requesting to resend the form.
+</p>
+<div id="console"></div>
+
+<script>
+var loaded = false;
+function runTest()
+{
+    if (window.layoutTestController) {
+        layoutTestController.dumpAsText();
+        layoutTestController.waitUntilDone();
+    }
+    
+    loaded = true;
+    setTimeout(function() { layoutTestController.notifyDone(); }, 200);
+}
+
+function clickLink()
+{
+    var frame = document.getElementById("frame");
+    var link = window.frames[0].document.getElementById("link");
+    if (window.eventSender) {
+        eventSender.mouseMoveTo(link.offsetLeft + frame.offsetLeft + 10, link.offsetTop + frame.offsetTop + 3);
+        eventSender.mouseDown();
+        eventSender.mouseUp();
+    }
+}
+
+function getTitle()
+{
+    return window.frames[0].document.querySelector("h1").innerText;
+}
+
+var step = 0;
+var step2output;
+function nextStep()
+{
+    if (!loaded) {
+        setTimeout(nextStep, 10);
+        return;
+    }
+
+    switch (step++) {
+    case 0:
+        shouldBeEqualToString("getTitle()", "Page 1");
+        setTimeout(clickLink, 0);
+        break;
+    case 1:
+        shouldBeEqualToString("getTitle()", "Page 2");
+        step2output = window.frames[0].document.getElementById("submissionTime").innerText;
+        setTimeout(clickLink, 0);
+        break;
+    case 2:
+        shouldBeEqualToString("getTitle()", "Page 3");
+        setTimeout(clickLink, 0);
+        break;
+    case 3:
+        shouldBeEqualToString("getTitle()", "Page 2");
+        shouldBe("window.frames[0].document.getElementById('submissionTime').innerText", "step2output");
+        if (window.layoutTestController);
+            layoutTestController.notifyDone();
+        break;
+    }
+}
+
+successfullyParsed = true;
+</script>
+<script src="../resources/js-test-post.js"></script>
+</body>
+</html>
\ No newline at end of file
diff --git a/LayoutTests/http/tests/loading/resources/post-in-iframe-with-back-navigation-page-1.php b/LayoutTests/http/tests/loading/resources/post-in-iframe-with-back-navigation-page-1.php
new file mode 100644 (file)
index 0000000..3789b5e
--- /dev/null
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<h1>Page 1</h1>
+<span id="submissionTime"><?php print microtime();?></span><br/>
+<form action="./post-in-iframe-with-back-navigation-page-2.php" name="form" method="POST">
+</form>
+<a id="link" href="javascript:document.form.submit();">to page 2</a>
diff --git a/LayoutTests/http/tests/loading/resources/post-in-iframe-with-back-navigation-page-2.php b/LayoutTests/http/tests/loading/resources/post-in-iframe-with-back-navigation-page-2.php
new file mode 100644 (file)
index 0000000..c43ebbc
--- /dev/null
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<h1>Page 2</h1>
+<span id="submissionTime"><?php print microtime();?></span><br/>
+<form action="./post-in-iframe-with-back-navigation-page-3.php" name="form" method="POST">
+</form>
+<a id="link" href="javascript:document.form.submit();">to page 3</a><br/>
+<a id="backLink" href="javascript:history.back();">go back</a>
diff --git a/LayoutTests/http/tests/loading/resources/post-in-iframe-with-back-navigation-page-3.php b/LayoutTests/http/tests/loading/resources/post-in-iframe-with-back-navigation-page-3.php
new file mode 100644 (file)
index 0000000..896c08e
--- /dev/null
@@ -0,0 +1,4 @@
+<!DOCTYPE html>
+<h1>Page 3</h1>
+<span id="submissionTime"><?php print microtime();?></span><br/>
+<a id="link" href="javascript:history.back();">go back</a>
diff --git a/LayoutTests/http/tests/resources/js-test-post.js b/LayoutTests/http/tests/resources/js-test-post.js
new file mode 100644 (file)
index 0000000..11a9e5f
--- /dev/null
@@ -0,0 +1,9 @@
+wasPostTestScriptParsed = true;
+
+if (window.jsTestIsAsync) {
+    if (window.layoutTestController)
+        layoutTestController.waitUntilDone();
+    if (window.wasFinishJSTestCalled)
+        finishJSTest();
+} else
+    finishJSTest();
diff --git a/LayoutTests/http/tests/resources/js-test-pre.js b/LayoutTests/http/tests/resources/js-test-pre.js
new file mode 100644 (file)
index 0000000..0aa417d
--- /dev/null
@@ -0,0 +1,526 @@
+// svg/dynamic-updates tests set enablePixelTesting=true, as we want to dump text + pixel results
+if (self.layoutTestController)
+    layoutTestController.dumpAsText(self.enablePixelTesting);
+
+var description, debug, successfullyParsed, errorMessage;
+
+(function() {
+
+    function getOrCreate(id, tagName)
+    {
+        var element = document.getElementById(id);
+        if (element)
+            return element;
+
+        element = document.createElement(tagName);
+        element.id = id;
+        var refNode;
+        var parent = document.body || document.documentElement;
+        if (id == "description")
+            refNode = getOrCreate("console", "div");
+        else
+            refNode = parent.firstChild;
+
+        parent.insertBefore(element, refNode);
+        return element;
+    }
+
+    description = function description(msg, quiet)
+    {
+        // For MSIE 6 compatibility
+        var span = document.createElement("span");
+        if (quiet)
+            span.innerHTML = '<p>' + msg + '</p><p>On success, you will see no "<span class="fail">FAIL</span>" messages, followed by "<span class="pass">TEST COMPLETE</span>".</p>';
+        else
+            span.innerHTML = '<p>' + msg + '</p><p>On success, you will see a series of "<span class="pass">PASS</span>" messages, followed by "<span class="pass">TEST COMPLETE</span>".</p>';
+
+        var description = getOrCreate("description", "p");
+        if (description.firstChild)
+            description.replaceChild(span, description.firstChild);
+        else
+            description.appendChild(span);
+    };
+
+    debug = function debug(msg)
+    {
+        var span = document.createElement("span");
+        getOrCreate("console", "div").appendChild(span); // insert it first so XHTML knows the namespace
+        span.innerHTML = msg + '<br />';
+    };
+
+    var css =
+        ".pass {" +
+            "font-weight: bold;" +
+            "color: green;" +
+        "}" +
+        ".fail {" +
+            "font-weight: bold;" +
+            "color: red;" +
+        "}" +
+        "#console {" +
+            "white-space: pre-wrap;" +
+            "font-family: monospace;" +
+        "}";
+
+    function insertStyleSheet()
+    {
+        var styleElement = document.createElement("style");
+        styleElement.textContent = css;
+        (document.head || document.documentElement).appendChild(styleElement);
+    }
+    
+    if (!isWorker())
+        insertStyleSheet();
+
+    self.onerror = function(message)
+    {
+        errorMessage = message;
+    };
+
+})();
+
+function isWorker()
+{
+    // It's conceivable that someone would stub out 'document' in a worker so
+    // also check for childNodes, an arbitrary DOM-related object that is
+    // meaningless in a WorkerContext.
+    return (typeof document === 'undefined' || typeof document.childNodes === 'undefined') && !!self.importScripts;
+}
+
+function descriptionQuiet(msg) { description(msg, true); }
+
+function escapeHTML(text)
+{
+    return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/\0/g, "\\0");
+}
+
+function testPassed(msg)
+{
+    debug('<span><span class="pass">PASS</span> ' + escapeHTML(msg) + '</span>');
+}
+
+function testFailed(msg)
+{
+    debug('<span><span class="fail">FAIL</span> ' + escapeHTML(msg) + '</span>');
+}
+
+function areArraysEqual(_a, _b)
+{
+    try {
+        if (_a.length !== _b.length)
+            return false;
+        for (var i = 0; i < _a.length; i++)
+            if (_a[i] !== _b[i])
+                return false;
+    } catch (ex) {
+        return false;
+    }
+    return true;
+}
+
+function isMinusZero(n)
+{
+    // the only way to tell 0 from -0 in JS is the fact that 1/-0 is
+    // -Infinity instead of Infinity
+    return n === 0 && 1/n < 0;
+}
+
+function isResultCorrect(_actual, _expected)
+{
+    if (_expected === 0)
+        return _actual === _expected && (1/_actual) === (1/_expected);
+    if (_actual === _expected)
+        return true;
+    if (typeof(_expected) == "number" && isNaN(_expected))
+        return typeof(_actual) == "number" && isNaN(_actual);
+    if (_expected && (Object.prototype.toString.call(_expected) == Object.prototype.toString.call([])))
+        return areArraysEqual(_actual, _expected);
+    return false;
+}
+
+function stringify(v)
+{
+    if (v === 0 && 1/v < 0)
+        return "-0";
+    else return "" + v;
+}
+
+function evalAndLog(_a)
+{
+  if (typeof _a != "string")
+    debug("WARN: tryAndLog() expects a string argument");
+
+  // Log first in case things go horribly wrong or this causes a sync event.
+  debug(_a);
+
+  var _av;
+  try {
+     _av = eval(_a);
+  } catch (e) {
+    testFailed(_a + " threw exception " + e);
+  }
+  return _av;
+}
+
+function shouldBe(_a, _b, quiet)
+{
+  if (typeof _a != "string" || typeof _b != "string")
+    debug("WARN: shouldBe() expects string arguments");
+  var exception;
+  var _av;
+  try {
+     _av = eval(_a);
+  } catch (e) {
+     exception = e;
+  }
+  var _bv = eval(_b);
+
+  if (exception)
+    testFailed(_a + " should be " + _bv + ". Threw exception " + exception);
+  else if (isResultCorrect(_av, _bv)) {
+    if (!quiet) {
+        testPassed(_a + " is " + _b);
+    }
+  } else if (typeof(_av) == typeof(_bv))
+    testFailed(_a + " should be " + _bv + ". Was " + stringify(_av) + ".");
+  else
+    testFailed(_a + " should be " + _bv + " (of type " + typeof _bv + "). Was " + _av + " (of type " + typeof _av + ").");
+}
+
+// Variant of shouldBe()--confirms that result of eval(_to_eval) is within
+// numeric _tolerance of numeric _target.
+function shouldBeCloseTo(_to_eval, _target, _tolerance, quiet)
+{
+  if (typeof _to_eval != "string") {
+    testFailed("shouldBeCloseTo() requires string argument _to_eval. was type " + typeof _to_eval);
+    return;
+  }
+  if (typeof _target != "number") {
+    testFailed("shouldBeCloseTo() requires numeric argument _target. was type " + typeof _target);
+    return;
+  }
+  if (typeof _tolerance != "number") {
+    testFailed("shouldBeCloseTo() requires numeric argument _tolerance. was type " + typeof _tolerance);
+    return;
+  }
+
+  var _result;
+  try {
+     _result = eval(_to_eval);
+  } catch (e) {
+    testFailed(_to_eval + " should be within " + _tolerance + " of "
+               + _target + ". Threw exception " + e);
+    return;
+  }
+
+  if (typeof(_result) != typeof(_target)) {
+    testFailed(_to_eval + " should be of type " + typeof _target
+               + " but was of type " + typeof _result);
+  } else if (Math.abs(_result - _target) <= _tolerance) {
+    if (!quiet) {
+        testPassed(_to_eval + " is within " + _tolerance + " of " + _target);
+    }
+  } else {
+    testFailed(_to_eval + " should be within " + _tolerance + " of " + _target
+               + ". Was " + _result + ".");
+  }
+}
+
+function shouldNotBe(_a, _b, quiet)
+{
+  if (typeof _a != "string" || typeof _b != "string")
+    debug("WARN: shouldNotBe() expects string arguments");
+  var exception;
+  var _av;
+  try {
+     _av = eval(_a);
+  } catch (e) {
+     exception = e;
+  }
+  var _bv = eval(_b);
+
+  if (exception)
+    testFailed(_a + " should not be " + _bv + ". Threw exception " + exception);
+  else if (!isResultCorrect(_av, _bv)) {
+    if (!quiet) {
+        testPassed(_a + " is not " + _b);
+    }
+  } else
+    testFailed(_a + " should not be " + _bv + ".");
+}
+
+function shouldBeTrue(_a) { shouldBe(_a, "true"); }
+function shouldBeTrueQuiet(_a) { shouldBe(_a, "true", true); }
+function shouldBeFalse(_a) { shouldBe(_a, "false"); }
+function shouldBeNaN(_a) { shouldBe(_a, "NaN"); }
+function shouldBeNull(_a) { shouldBe(_a, "null"); }
+function shouldBeZero(_a) { shouldBe(_a, "0"); }
+
+function shouldBeEqualToString(a, b)
+{
+  var unevaledString = '"' + b.replace(/\\/g, "\\\\").replace(/"/g, "\"").replace(/\n/g, "\\n").replace(/\r/g, "\\r") + '"';
+  shouldBe(a, unevaledString);
+}
+
+function shouldBeEmptyString(_a) { shouldBeEqualToString(_a, ""); }
+
+function shouldEvaluateTo(actual, expected) {
+  // A general-purpose comparator.  'actual' should be a string to be
+  // evaluated, as for shouldBe(). 'expected' may be any type and will be
+  // used without being eval'ed.
+  if (expected == null) {
+    // Do this before the object test, since null is of type 'object'.
+    shouldBeNull(actual);
+  } else if (typeof expected == "undefined") {
+    shouldBeUndefined(actual);
+  } else if (typeof expected == "function") {
+    // All this fuss is to avoid the string-arg warning from shouldBe().
+    try {
+      actualValue = eval(actual);
+    } catch (e) {
+      testFailed("Evaluating " + actual + ": Threw exception " + e);
+      return;
+    }
+    shouldBe("'" + actualValue.toString().replace(/\n/g, "") + "'",
+             "'" + expected.toString().replace(/\n/g, "") + "'");
+  } else if (typeof expected == "object") {
+    shouldBeTrue(actual + " == '" + expected + "'");
+  } else if (typeof expected == "string") {
+    shouldBe(actual, expected);
+  } else if (typeof expected == "boolean") {
+    shouldBe("typeof " + actual, "'boolean'");
+    if (expected)
+      shouldBeTrue(actual);
+    else
+      shouldBeFalse(actual);
+  } else if (typeof expected == "number") {
+    shouldBe(actual, stringify(expected));
+  } else {
+    debug(expected + " is unknown type " + typeof expected);
+    shouldBeTrue(actual, "'"  +expected.toString() + "'");
+  }
+}
+
+function shouldBeNonZero(_a)
+{
+  var exception;
+  var _av;
+  try {
+     _av = eval(_a);
+  } catch (e) {
+     exception = e;
+  }
+
+  if (exception)
+    testFailed(_a + " should be non-zero. Threw exception " + exception);
+  else if (_av != 0)
+    testPassed(_a + " is non-zero.");
+  else
+    testFailed(_a + " should be non-zero. Was " + _av);
+}
+
+function shouldBeNonNull(_a)
+{
+  var exception;
+  var _av;
+  try {
+     _av = eval(_a);
+  } catch (e) {
+     exception = e;
+  }
+
+  if (exception)
+    testFailed(_a + " should be non-null. Threw exception " + exception);
+  else if (_av != null)
+    testPassed(_a + " is non-null.");
+  else
+    testFailed(_a + " should be non-null. Was " + _av);
+}
+
+function shouldBeUndefined(_a)
+{
+  var exception;
+  var _av;
+  try {
+     _av = eval(_a);
+  } catch (e) {
+     exception = e;
+  }
+
+  if (exception)
+    testFailed(_a + " should be undefined. Threw exception " + exception);
+  else if (typeof _av == "undefined")
+    testPassed(_a + " is undefined.");
+  else
+    testFailed(_a + " should be undefined. Was " + _av);
+}
+
+function shouldBeDefined(_a)
+{
+  var exception;
+  var _av;
+  try {
+     _av = eval(_a);
+  } catch (e) {
+     exception = e;
+  }
+
+  if (exception)
+    testFailed(_a + " should be defined. Threw exception " + exception);
+  else if (_av !== undefined)
+    testPassed(_a + " is defined.");
+  else
+    testFailed(_a + " should be defined. Was " + _av);
+}
+
+function shouldBeGreaterThanOrEqual(_a, _b) {
+    if (typeof _a != "string" || typeof _b != "string")
+        debug("WARN: shouldBeGreaterThanOrEqual expects string arguments");
+
+    var exception;
+    var _av;
+    try {
+        _av = eval(_a);
+    } catch (e) {
+        exception = e;
+    }
+    var _bv = eval(_b);
+
+    if (exception)
+        testFailed(_a + " should be >= " + _b + ". Threw exception " + exception);
+    else if (typeof _av == "undefined" || _av < _bv)
+        testFailed(_a + " should be >= " + _b + ". Was " + _av + " (of type " + typeof _av + ").");
+    else
+        testPassed(_a + " is >= " + _b);
+}
+
+function shouldThrow(_a, _e)
+{
+  var exception;
+  var _av;
+  try {
+     _av = eval(_a);
+  } catch (e) {
+     exception = e;
+  }
+
+  var _ev;
+  if (_e)
+      _ev =  eval(_e);
+
+  if (exception) {
+    if (typeof _e == "undefined" || exception == _ev)
+      testPassed(_a + " threw exception " + exception + ".");
+    else
+      testFailed(_a + " should throw " + (typeof _e == "undefined" ? "an exception" : _ev) + ". Threw exception " + exception + ".");
+  } else if (typeof _av == "undefined")
+    testFailed(_a + " should throw " + (typeof _e == "undefined" ? "an exception" : _ev) + ". Was undefined.");
+  else
+    testFailed(_a + " should throw " + (typeof _e == "undefined" ? "an exception" : _ev) + ". Was " + _av + ".");
+}
+
+function shouldHaveHadError(message)
+{
+    if (errorMessage) {
+        if (!message)
+            testPassed("Got expected error");
+        else if (errorMessage.indexOf(message) !== -1)
+            testPassed("Got expected error: '" + message + "'");
+        else
+            testFailed("Unexpexted error '" + message + "'");
+    } else
+        testFailed("Missing expexted error");
+    errorMessage = undefined;
+}
+
+function gc() {
+    if (typeof GCController !== "undefined")
+        GCController.collect();
+    else {
+        var gcRec = function (n) {
+            if (n < 1)
+                return {};
+            var temp = {i: "ab" + i + (i / 100000)};
+            temp += "foo";
+            gcRec(n-1);
+        };
+        for (var i = 0; i < 1000; i++)
+            gcRec(10)
+    }
+}
+
+function isSuccessfullyParsed()
+{
+    // FIXME: Remove this and only report unexpected syntax errors.
+    if (!errorMessage)
+        successfullyParsed = true;
+    shouldBeTrue("successfullyParsed");
+    debug('<br /><span class="pass">TEST COMPLETE</span>');
+}
+
+// It's possible for an async test to call finishJSTest() before js-test-post.js
+// has been parsed.
+function finishJSTest()
+{
+    wasFinishJSTestCalled = true;
+    if (!self.wasPostTestScriptParsed)
+        return;
+    isSuccessfullyParsed();
+    if (self.jsTestIsAsync && self.layoutTestController)
+        layoutTestController.notifyDone();
+}
+
+function startWorker(testScriptURL, shared)
+{
+    self.jsTestIsAsync = true;
+    debug('Starting worker: ' + testScriptURL);
+    var worker = shared ? new SharedWorker(testScriptURL) : new Worker(testScriptURL);
+    if (shared)
+        worker.port.onmessage = function(event) { worker.onmessage(event); };
+    worker.onmessage = function(event)
+    {
+        var workerPrefix = "[Worker] ";
+        if (event.data.length < 5 || event.data.charAt(4) != ':') {
+          debug(workerPrefix + event.data);
+          return;
+        }
+        var code = event.data.substring(0, 4);
+        var payload = workerPrefix + event.data.substring(5);
+        if (code == "PASS")
+            testPassed(payload);
+        else if (code == "FAIL")
+            testFailed(payload);
+        else if (code == "DESC")
+            description(payload);
+        else if (code == "DONE")
+            finishJSTest();
+        else
+            debug(workerPrefix + event.data);
+    };
+
+    worker.onerror = function(event)
+    {
+        debug('Got error from worker: ' + event.message);
+        finishJSTest();
+    }
+
+    return worker;
+}
+
+if (isWorker()) {
+    description = function(msg, quiet) {
+        postMessage('DESC:' + msg);
+    }
+    testFailed = function(msg) {
+        postMessage('FAIL:' + msg);
+    }
+    testPassed = function(msg) {
+        postMessage('PASS:' + msg);
+    }
+    finishJSTest = function() {
+        postMessage('DONE:');
+    }
+    debug = function(msg) {
+        postMessage(msg);
+    }
+}
index df6f057..bd48908 100644 (file)
@@ -1,3 +1,21 @@
+2012-05-08  Jon Lee  <jonlee@apple.com>
+
+        Safari warns that it needs to resend the form in an iFrame when going back
+        https://bugs.webkit.org/show_bug.cgi?id=82658
+        <rdar://problem/11292558>
+
+        Reviewed by Darin Adler.
+
+        Test: http/tests/loading/post-in-iframe-with-back-navigation.html
+
+        * WebCore.exp.in: Add _wkCFURLRequestAllowAllPostCaching.
+        * platform/mac/WebCoreSystemInterface.h: Add wkCFURLRequestAllowAllPostCaching.
+        * platform/mac/WebCoreSystemInterface.mm: Add wkCFURLRequestAllowAllPostCaching.
+        * platform/network/cf/ResourceRequestCFNet.cpp:
+        (WebCore::ResourceRequest::doUpdatePlatformRequest): Set the bit to cache all POST responses.
+        * platform/network/mac/ResourceRequestMac.mm:
+        (WebCore::ResourceRequest::doUpdatePlatformRequest): Set the bit to cache all POST responses.
+
 2012-05-08  Dana Jansens  <danakj@chromium.org>
 
         [chromium] Reflections with masks should not occlude
index b294d0b..e6c293e 100644 (file)
@@ -1553,6 +1553,9 @@ _wkAdvanceDefaultButtonPulseAnimation
 #if !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
 _wkCALayerEnumerateRectsBeingDrawnWithBlock
 #endif
+#if !defined(BUILDING_ON_SNOW_LEOPARD)
+_wkCFURLRequestAllowAllPostCaching
+#endif
 _wkCGContextGetShouldSmoothFonts
 _wkCGContextResetClip
 #if !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
index 12efb98..9abc123 100644 (file)
@@ -323,4 +323,8 @@ extern const char* (*wkFilterDataComplete)(WebFilterEvaluator *, int* length);
 
 }
 
+#if !defined(BUILDING_ON_SNOW_LEOPARD)
+extern void (*wkCFURLRequestAllowAllPostCaching)(CFURLRequestRef);
+#endif
+
 #endif
index 2cd6af2..439a2f2 100644 (file)
@@ -191,6 +191,10 @@ bool (*wkExecutableWasLinkedOnOrBeforeLion)(void);
 void (*wkCGPathAddRoundedRect)(CGMutablePathRef path, const CGAffineTransform* matrix, CGRect rect, CGFloat cornerWidth, CGFloat cornerHeight);
 #endif
 
+#if !defined(BUILDING_ON_SNOW_LEOPARD)
+void (*wkCFURLRequestAllowAllPostCaching)(CFURLRequestRef);
+#endif
+
 #if !defined(BUILDING_ON_SNOW_LEOPARD) && !defined(BUILDING_ON_LION) && !PLATFORM(IOS)
 BOOL (*wkFilterIsManagedSession)(void);
 WebFilterEvaluator *(*wkFilterCreateInstance)(NSURLResponse *);
index 279d755..7ce9b60 100644 (file)
@@ -151,6 +151,9 @@ void ResourceRequest::doUpdatePlatformRequest()
 
     if (httpPipeliningEnabled())
         wkSetHTTPPipeliningPriority(cfRequest, toHTTPPipeliningPriority(m_priority));
+#if !PLATFORM(WIN)
+    wkCFURLRequestAllowAllPostCaching(cfRequest);
+#endif
 
     setHeaderFields(cfRequest, httpHeaderFields());
     RefPtr<FormData> formData = httpBody();
index 120f4ac..262fdb4 100644 (file)
@@ -135,6 +135,9 @@ void ResourceRequest::doUpdatePlatformRequest()
 #endif
 
     [nsRequest setCachePolicy:(NSURLRequestCachePolicy)cachePolicy()];
+#if !defined(BUILDING_ON_SNOW_LEOPARD)
+    wkCFURLRequestAllowAllPostCaching([nsRequest _CFURLRequest]);
+#endif
 
     double timeoutInterval = ResourceRequestBase::timeoutInterval();
     if (timeoutInterval)
index 55500d8..2ec14a4 100644 (file)
@@ -1,3 +1,14 @@
+2012-05-08  Jon Lee  <jonlee@apple.com>
+
+        Safari warns that it needs to resend the form in an iFrame when going back
+        https://bugs.webkit.org/show_bug.cgi?id=82658
+        <rdar://problem/11292558>
+
+        Reviewed by Darin Adler.
+
+        * WebCoreSupport/WebSystemInterface.mm:
+        (InitWebCoreSystemInterface): Add wkCFURLRequestAllowAllPostCaching.
+
 2012-05-08  Timothy Hatcher  <timothy@apple.com>
 
         Fix the SOFT_LINK_STAGED_FRAMEWORK_OPTIONAL macro so it passes the full path to dlopen.
index 06a3ea3..86a51c1 100644 (file)
@@ -184,6 +184,10 @@ void InitWebCoreSystemInterface(void)
     INIT(CGPathAddRoundedRect);
 #endif
 
+#if !defined(BUILDING_ON_SNOW_LEOPARD)
+    INIT(CFURLRequestAllowAllPostCaching);
+#endif
+
 #if PLATFORM(MAC) && !defined(BUILDING_ON_SNOW_LEOPARD) && !defined(BUILDING_ON_LION) && !PLATFORM(IOS)
     INIT(FilterIsManagedSession);
     INIT(FilterCreateInstance);
index c624e44..28d5633 100644 (file)
@@ -1,3 +1,14 @@
+2012-05-08  Jon Lee  <jonlee@apple.com>
+
+        Safari warns that it needs to resend the form in an iFrame when going back
+        https://bugs.webkit.org/show_bug.cgi?id=82658
+        <rdar://problem/11292558>
+
+        Reviewed by Darin Adler.
+
+        * WebProcess/WebCoreSupport/mac/WebSystemInterface.mm:
+        (InitWebCoreSystemInterface): Add wkCFURLRequestAllowAllPostCaching.
+
 2012-05-08  Anders Carlsson  <andersca@apple.com>
 
         Can't scroll PDF in subframe
index 37a6841..acf19c4 100644 (file)
@@ -171,6 +171,9 @@ void InitWebCoreSystemInterface(void)
         INIT(CGPathAddRoundedRect);
 #endif
 
+#if !defined(BUILDING_ON_SNOW_LEOPARD)
+        INIT(CFURLRequestAllowAllPostCaching);
+#endif
 #if PLATFORM(MAC) && !defined(BUILDING_ON_SNOW_LEOPARD) && !defined(BUILDING_ON_LION) && !PLATFORM(IOS)
         INIT(FilterIsManagedSession);
         INIT(FilterCreateInstance);
index 2820491..2f63236 100644 (file)
@@ -1,3 +1,16 @@
+2012-05-08  Jon Lee  <jonlee@apple.com>
+
+        Safari warns that it needs to resend the form in an iFrame when going back
+        https://bugs.webkit.org/show_bug.cgi?id=82658
+        <rdar://problem/11292558>
+
+        Reviewed by Darin Adler.
+
+        * WebKitSystemInterface.h:
+        * libWebKitSystemInterfaceLeopard.a:
+        * libWebKitSystemInterfaceLion.a:
+        * libWebKitSystemInterfaceSnowLeopard.a:
+
 2012-05-07  Eric Seidel  <eric@webkit.org>
 
         Add ENABLE_IFRAME_SEAMLESS so Apple can turn off SEAMLESS if needed
index a67c874..f43b30d 100644 (file)
@@ -488,6 +488,21 @@ bool WKExecutableWasLinkedOnOrBeforeLion(void);
 void WKCGPathAddRoundedRect(CGMutablePathRef path, const CGAffineTransform* matrix, CGRect rect, CGFloat cornerWidth, CGFloat cornerHeight);
 #endif
 
+#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
+void WKCFURLRequestAllowAllPostCaching(CFURLRequestRef);
+#endif
+
+#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1080
+@class WebFilterEvaluator;
+
+BOOL WKFilterIsManagedSession(void);
+WebFilterEvaluator *WKFilterCreateInstance(NSURLResponse *);
+void WKFilterRelease(WebFilterEvaluator *);
+BOOL WKFilterWasBlocked(WebFilterEvaluator *);
+const char* WKFilterAddData(WebFilterEvaluator *, const char* data, int* length);
+const char* WKFilterDataComplete(WebFilterEvaluator *, int* length);
+#endif
+
 #ifdef __cplusplus
 }
 #endif
index 868149c..33116d8 100644 (file)
Binary files a/WebKitLibraries/libWebKitSystemInterfaceLeopard.a and b/WebKitLibraries/libWebKitSystemInterfaceLeopard.a differ
index add5b2f..43cdad5 100644 (file)
Binary files a/WebKitLibraries/libWebKitSystemInterfaceLion.a and b/WebKitLibraries/libWebKitSystemInterfaceLion.a differ
index bf3fae3..baff54a 100644 (file)
Binary files a/WebKitLibraries/libWebKitSystemInterfaceSnowLeopard.a and b/WebKitLibraries/libWebKitSystemInterfaceSnowLeopard.a differ