Reviewed by Darin.
authorap <ap@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 8 Dec 2006 18:19:51 +0000 (18:19 +0000)
committerap <ap@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 8 Dec 2006 18:19:51 +0000 (18:19 +0000)
        http://bugs.webkit.org/show_bug.cgi?id=9854
        HTTP Refresh header with quotes is parsed incorrectly

        Test: http/tests/misc/redirect-with-quotes.php

        * WebCore.xcodeproj/project.pbxproj:
        Added HTTPParsers.{h,cpp}. I intend to move Content-Type parsing here, as well.

        * dom/Document.cpp:
        (WebCore::Document::processHttpEquiv):
        * loader/FrameLoader.cpp:
        (WebCore::FrameLoader::receivedFirstData):
        Use the new implementation in HTTPHeaders.

        * platform/network/HTTPParsers.cpp: Added.
        (WebCore::skipWhiteSpace):
        (WebCore::parseHTTPRefresh):
        * platform/network/HTTPParsers.h: Added.
        Merged and rewrote existing implementations for better Firefox compatibility.

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

12 files changed:
LayoutTests/ChangeLog
LayoutTests/http/tests/misc/redirect-with-quotes-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/misc/redirect-with-quotes.php [new file with mode: 0644]
LayoutTests/http/tests/misc/resources/redirect-step2.php [new file with mode: 0644]
LayoutTests/http/tests/misc/resources/redirect-step3.php [new file with mode: 0644]
LayoutTests/http/tests/misc/resources/redirect-step4.php [new file with mode: 0644]
WebCore/ChangeLog
WebCore/WebCore.xcodeproj/project.pbxproj
WebCore/dom/Document.cpp
WebCore/loader/FrameLoader.cpp
WebCore/platform/network/HTTPParsers.cpp [new file with mode: 0644]
WebCore/platform/network/HTTPParsers.h [new file with mode: 0644]

index 389b4be06aa6fd29a47a485fbc320a6538badc7d..58a77499e33d9aede9cfbeca0fd3f6df4b7471be 100644 (file)
@@ -1,3 +1,16 @@
+2006-12-08  Alexey Proskuryakov  <ap@webkit.org>
+
+        Reviewed by Darin.
+
+        Test for http://bugs.webkit.org/show_bug.cgi?id=9854
+        HTTP Refresh header with quotes is parsed incorrectly
+
+        * http/tests/misc/redirect-with-quotes-expected.txt: Added.
+        * http/tests/misc/redirect-with-quotes.php: Added.
+        * http/tests/misc/resources/redirect-step2.php: Added.
+        * http/tests/misc/resources/redirect-step3.php: Added.
+        * http/tests/misc/resources/redirect-step4.php: Added.
+
 2006-12-08  Alexey Proskuryakov  <ap@webkit.org>
 
         Reviewed by Tim H.
diff --git a/LayoutTests/http/tests/misc/redirect-with-quotes-expected.txt b/LayoutTests/http/tests/misc/redirect-with-quotes-expected.txt
new file mode 100644 (file)
index 0000000..ff43ca4
--- /dev/null
@@ -0,0 +1 @@
+SUCCESS
diff --git a/LayoutTests/http/tests/misc/redirect-with-quotes.php b/LayoutTests/http/tests/misc/redirect-with-quotes.php
new file mode 100644 (file)
index 0000000..98beabe
--- /dev/null
@@ -0,0 +1,18 @@
+<?php
+  // Test for various syntaxes of Refresh header, 
+  // <http://bugzilla.opendarwin.org/show_bug.cgi?id=9854>.
+
+  header('Content-type: text/html');
+  header('Refresh: 0, URL      =       "resources/redirect-step2.php"');
+?>
+
+<body>
+<script>
+   if (window.layoutTestController) {
+       layoutTestController.waitUntilDone();
+       layoutTestController.dumpAsText();
+   }
+</script>
+   
+<p>FAILURE - should redirect (1)<p>
+</body>
diff --git a/LayoutTests/http/tests/misc/resources/redirect-step2.php b/LayoutTests/http/tests/misc/resources/redirect-step2.php
new file mode 100644 (file)
index 0000000..2713b44
--- /dev/null
@@ -0,0 +1,9 @@
+<?php
+  // Test for various syntaxes of Refresh header, 
+  // <http://bugzilla.opendarwin.org/show_bug.cgi?id=9854>.
+
+  header('Content-type: text/html');
+  header('Refresh:     0       ;       url=    \'redirect-step3.php\'  ');
+?>
+
+<p>FAILURE - should redirect (2)<p>
diff --git a/LayoutTests/http/tests/misc/resources/redirect-step3.php b/LayoutTests/http/tests/misc/resources/redirect-step3.php
new file mode 100644 (file)
index 0000000..ec0a016
--- /dev/null
@@ -0,0 +1,11 @@
+<?php
+  // Test for various syntaxes of Refresh header, 
+  // <http://bugzilla.opendarwin.org/show_bug.cgi?id=9854>.
+
+  header('Content-type: text/html');
+?>
+<head>
+  <meta http-equiv="Refresh" content=" 0, 'redirect-step4.php' ">
+</head>
+
+<p>FAILURE - should redirect (3)<p>
diff --git a/LayoutTests/http/tests/misc/resources/redirect-step4.php b/LayoutTests/http/tests/misc/resources/redirect-step4.php
new file mode 100644 (file)
index 0000000..8249213
--- /dev/null
@@ -0,0 +1,11 @@
+<?php
+  // Test for various syntaxes of Refresh header, 
+  // <http://bugzilla.opendarwin.org/show_bug.cgi?id=9854>.
+
+  header('Content-type: text/html');
+?>
+<head>
+  <meta http-equiv="Refresh" content=' 0        ;      200.html        '>
+</head>
+
+<p>FAILURE - should redirect (4)<p>
index e33c1cb847d3a0e957370c96a51e300dcb45017a..5b62c3605a13650c618c269dc6b357b5e190037a 100644 (file)
@@ -1,3 +1,27 @@
+2006-12-08  Alexey Proskuryakov  <ap@webkit.org>
+
+        Reviewed by Darin.
+
+        http://bugs.webkit.org/show_bug.cgi?id=9854
+        HTTP Refresh header with quotes is parsed incorrectly
+
+        Test: http/tests/misc/redirect-with-quotes.php
+
+        * WebCore.xcodeproj/project.pbxproj:
+        Added HTTPParsers.{h,cpp}. I intend to move Content-Type parsing here, as well.
+
+        * dom/Document.cpp:
+        (WebCore::Document::processHttpEquiv):
+        * loader/FrameLoader.cpp:
+        (WebCore::FrameLoader::receivedFirstData):
+        Use the new implementation in HTTPHeaders.
+
+        * platform/network/HTTPParsers.cpp: Added.
+        (WebCore::skipWhiteSpace):
+        (WebCore::parseHTTPRefresh):
+        * platform/network/HTTPParsers.h: Added.
+        Merged and rewrote existing implementations for better Firefox compatibility.
+
 2006-12-08  Alexey Proskuryakov  <ap@webkit.org>
 
         Reviewed by Tim H.
index f97505c1ea94e06c9d4e15e48d19d3c43957e9be..8364242273d71f7582603de287ad2503a477d14c 100644 (file)
                E14842FF0A674A31007E4D39 /* TextCodecICU.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E14842FE0A674A31007E4D39 /* TextCodecICU.cpp */; };
                E148432F0A674FC2007E4D39 /* TextCodecMac.h in Headers */ = {isa = PBXBuildFile; fileRef = E148432E0A674FC2007E4D39 /* TextCodecMac.h */; };
                E14843D60A6754A6007E4D39 /* TextCodecMac.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E14843910A6752BF007E4D39 /* TextCodecMac.cpp */; };
+               E1D8E3160B29E39C00F4BAF6 /* HTTPParsers.h in Headers */ = {isa = PBXBuildFile; fileRef = E1D8E3150B29E39C00F4BAF6 /* HTTPParsers.h */; };
+               E1D8E31A0B29E3B600F4BAF6 /* HTTPParsers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E1D8E3190B29E3B600F4BAF6 /* HTTPParsers.cpp */; };
                E1EBBBD40AAC9B87001FE8E2 /* CSSCharsetRule.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E1EBBBD30AAC9B87001FE8E2 /* CSSCharsetRule.cpp */; };
                E1F0424609839389006694EA /* xmlhttprequest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E1F0424409839389006694EA /* xmlhttprequest.cpp */; };
                E1F0424709839389006694EA /* xmlhttprequest.h in Headers */ = {isa = PBXBuildFile; fileRef = E1F0424509839389006694EA /* xmlhttprequest.h */; };
                E14842FE0A674A31007E4D39 /* TextCodecICU.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TextCodecICU.cpp; sourceTree = "<group>"; };
                E148432E0A674FC2007E4D39 /* TextCodecMac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; name = TextCodecMac.h; path = mac/TextCodecMac.h; sourceTree = "<group>"; };
                E14843910A6752BF007E4D39 /* TextCodecMac.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = TextCodecMac.cpp; path = mac/TextCodecMac.cpp; sourceTree = "<group>"; };
+               E1D8E3150B29E39C00F4BAF6 /* HTTPParsers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTTPParsers.h; sourceTree = "<group>"; };
+               E1D8E3190B29E3B600F4BAF6 /* HTTPParsers.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HTTPParsers.cpp; sourceTree = "<group>"; };
                E1EBBBD30AAC9B87001FE8E2 /* CSSCharsetRule.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CSSCharsetRule.cpp; sourceTree = "<group>"; };
                E1F0424409839389006694EA /* xmlhttprequest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = xmlhttprequest.cpp; sourceTree = "<group>"; };
                E1F0424509839389006694EA /* xmlhttprequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = xmlhttprequest.h; sourceTree = "<group>"; };
                                651888860AFF3BF700164720 /* ResourceError.cpp */,
                                651888870AFF3BF700164720 /* ResourceError.h */,
                                655A81BD0AEF67E6000975F0 /* HTTPHeaderMap.h */,
+                               E1D8E3150B29E39C00F4BAF6 /* HTTPParsers.h */,
+                               E1D8E3190B29E3B600F4BAF6 /* HTTPParsers.cpp */,
                                656B85370AEA1F9A00A095B4 /* ResourceHandle.h */,
                                656B84DC0AEA1D3100A095B4 /* ResourceHandle.cpp */,
                                656B84DE0AEA1D3100A095B4 /* ResourceHandleClient.h */,
                                B2310B770B1F46A200D55D87 /* CgSupport.h in Headers */,
                                932871C00B20DEB70049035A /* PlatformMenuDescription.h in Headers */,
                                B2BFB5A00B22F76200567E80 /* ImageAnimationObserver.h in Headers */,
+                               E1D8E3160B29E39C00F4BAF6 /* HTTPParsers.h in Headers */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                B277B4040B22F37C0004BEC6 /* GraphicsContextMac.mm in Sources */,
                                ED501DC60B249F2900AE18D9 /* EditorMac.mm in Sources */,
                                93354A3C0B24F8C9003F6DEA /* UIEventWithKeyState.cpp in Sources */,
+                               E1D8E31A0B29E3B600F4BAF6 /* HTTPParsers.cpp in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
index 4f5ff94b6771159aa9fcbb488ad81a039135db1e..d759612d02c79a159c2ea68e160923fb259ff210 100644 (file)
@@ -49,6 +49,8 @@
 #include "FrameLoader.h"
 #include "FrameTree.h"
 #include "FrameView.h"
+#include "HitTestRequest.h"
+#include "HitTestResult.h"
 #include "HTMLBodyElement.h"
 #include "HTMLDocument.h"
 #include "HTMLElementFactory.h"
@@ -59,8 +61,7 @@
 #include "HTMLNameCollection.h"
 #include "HTMLNames.h"
 #include "HTMLStyleElement.h"
-#include "HitTestRequest.h"
-#include "HitTestResult.h"
+#include "HTTPParsers.h"
 #include "JSEditor.h"
 #include "KeyboardEvent.h"
 #include "Logging.h"
@@ -1652,37 +1653,14 @@ void Document::processHttpEquiv(const String &equiv, const String &content)
         m_preferredStylesheetSet = content;
         updateStyleSelector();
     } else if (equalIgnoringCase(equiv, "refresh")) {
-        // get delay and url
-        DeprecatedString str = content.stripWhiteSpace().deprecatedString();
-        int pos = str.find(RegularExpression("[;,]"));
-        if (pos == -1)
-            pos = str.find(RegularExpression("[ \t]"));
-
-        if (pos == -1) // There can be no url (David)
-        {
-            bool ok = false;
-            double delay = 0;
-            delay = str.toDouble(&ok);
-            // We want a new history item if the refresh timeout > 1 second
-            if (ok && frame)
+        double delay;
+        String url;
+        if (frame && parseHTTPRefresh(content, delay, url)) {
+            if (url.isEmpty())
                 frame->loader()->scheduleRedirection(delay, frame->loader()->url().url(), delay <= 1);
-        } else {
-            double delay = 0;
-            bool ok = false;
-            delay = str.left(pos).stripWhiteSpace().toDouble(&ok);
-
-            pos++;
-            while(pos < (int)str.length() && str[pos].isSpace()) pos++;
-            str = str.mid(pos);
-            if (str.find("url", 0,  false) == 0)
-                str = str.mid(3);
-            str = str.stripWhiteSpace();
-            if (str.length() && str[0] == '=')
-                str = str.mid(1).stripWhiteSpace();
-            str = parseURL(String(str)).deprecatedString();
-            if (ok && frame)
+            else
                 // We want a new history item if the refresh timeout > 1 second
-                frame->loader()->scheduleRedirection(delay, completeURL(str), delay <= 1);
+                frame->loader()->scheduleRedirection(delay, completeURL(url), delay <= 1);
         }
     } else if (equalIgnoringCase(equiv, "expires")) {
         String str = content.stripWhiteSpace();
index c3cbae5f06c22f158607ed4b5c3fbb07bd0c49e3..f9bf06cb1af8533a73bcbbaf564adf942352e5b1 100644 (file)
@@ -53,6 +53,7 @@
 #include "HTMLNames.h"
 #include "HTMLObjectElement.h"
 #include "HTMLPlugInElement.h"
+#include "HTTPParsers.h"
 #include "IconDatabase.h"
 #include "IconLoader.h"
 #include "MainResourceLoader.h"
@@ -762,41 +763,17 @@ void FrameLoader::receivedFirstData()
     m_workingURL = KURL();
 
     const String& refresh = m_responseRefreshHeader;
-    if (refresh.isEmpty())
-        return;
 
     double delay;
     String URL;
 
-    int pos = refresh.find(';');
-    if (pos == -1)
-        pos = refresh.find(',');
-    if (pos == -1) {
-        delay = refresh.stripWhiteSpace().toDouble();
+    if (!parseHTTPRefresh(refresh, delay, URL))
+        return;
+
+    if (URL.isEmpty())
         URL = m_URL.url();
-    } else {
-        int endPos = refresh.length();
-        delay = refresh.left(pos).stripWhiteSpace().toDouble();
-        while (refresh[++pos] == ' ')
-            ;
-        if (refresh.find("url", pos, false) == pos) {
-            pos += 3;
-            while (refresh[pos] == ' ' || refresh[pos] == '=')
-                pos++;
-            if (refresh[pos] == '"') {
-                pos++;
-                int index = endPos - 1;
-                while (index > pos) {
-                    if (refresh[index] == '"')
-                        break;
-                    index--;
-                }
-                if (index > pos)
-                    endPos = index;
-            }
-        }
-        URL = m_frame->document()->completeURL(refresh.substring(pos, endPos - pos));
-    }
+    else
+        URL = m_frame->document()->completeURL(URL);
 
     // We want a new history item if the refresh timeout > 1 second
     scheduleRedirection(delay, URL, delay <= 1);
diff --git a/WebCore/platform/network/HTTPParsers.cpp b/WebCore/platform/network/HTTPParsers.cpp
new file mode 100644 (file)
index 0000000..886d709
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer. 
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution. 
+ * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ *     its contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "HTTPParsers.h"
+
+#include "PlatformString.h"
+
+namespace WebCore {
+
+// true if there is more to parse
+static inline bool skipWhiteSpace(const String& str, int& pos)
+{
+    int len = str.length();
+
+    while (pos != len && (str[pos] == '\t' || str[pos] == ' '))
+        ++pos;
+    return pos != len;
+}
+
+bool parseHTTPRefresh(const String& refresh, double& delay, String& url)
+{
+    int len = refresh.length();
+    int pos = 0;
+    
+    if (!skipWhiteSpace(refresh, pos))
+        return false;
+    
+    while (pos != len && refresh[pos] != ',' && refresh[pos] != ';')
+        ++pos;
+    
+    if (pos == len) { // no URL
+        url = String();
+        bool ok;
+        delay = refresh.stripWhiteSpace().toDouble(&ok);
+        return ok;
+    } else {
+        bool ok;
+        delay = refresh.left(pos).stripWhiteSpace().toDouble(&ok);
+        if (!ok)
+            return false;
+        
+        ++pos;
+        skipWhiteSpace(refresh, pos);
+        int urlStartPos = pos;
+        if (refresh.find("url", urlStartPos, false) == urlStartPos) {
+            urlStartPos += 3;
+            skipWhiteSpace(refresh, urlStartPos);
+            if (refresh[urlStartPos] == '=') {
+                ++urlStartPos;
+                skipWhiteSpace(refresh, urlStartPos);
+            } else
+                urlStartPos = pos;  // e.g. "Refresh: 0; url.html"
+        }
+
+        int urlEndPos = len;
+
+        if (refresh[urlStartPos] == '"' || refresh[urlStartPos] == '\'') {
+            UChar quotationMark = refresh[urlStartPos];
+            urlStartPos++;
+            while (urlEndPos > urlStartPos) {
+                urlEndPos--;
+                if (refresh[urlEndPos] == quotationMark)
+                    break;
+            }
+        }
+
+        url = refresh.substring(urlStartPos, urlEndPos - urlStartPos).stripWhiteSpace();
+        return true;
+    }
+}
+
+}
diff --git a/WebCore/platform/network/HTTPParsers.h b/WebCore/platform/network/HTTPParsers.h
new file mode 100644 (file)
index 0000000..ea41ce1
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer. 
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution. 
+ * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ *     its contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef HTTPParsers_h
+#define HTTPParsers_h
+
+namespace WebCore {
+
+    class String;
+
+    bool parseHTTPRefresh(const String& refresh, double& delay, String& url);
+}
+
+#endif