[BlackBerry] Add a check to filter out cookies that tries to set the domain to a...
[WebKit-https.git] / Source / WebCore / platform / blackberry / CookieParser.cpp
index f6fe962..2564c56 100644 (file)
@@ -29,6 +29,7 @@
 
 #include "Logging.h"
 #include "ParsedCookie.h"
+#include <network/DomainTools.h>
 #include <wtf/CurrentTime.h>
 #include <wtf/text/CString.h>
 
@@ -109,16 +110,21 @@ ParsedCookie* CookieParser::parseOneCookie(const String& cookie, unsigned start,
     unsigned tokenEnd = start; // Token end contains the position of the '=' or the end of a token
     unsigned pairEnd = start; // Pair end contains always the position of the ';'
 
-    // find the *first* ';' and the '=' (if they exist)
-    bool quoteFound = false;
+    // Find the first ';' which is not double-quoted and the '=' (if they exist).
     bool foundEqual = false;
-    while (pairEnd < end && (cookie[pairEnd] != ';' || quoteFound)) {
-        if (tokenEnd == start && cookie[pairEnd] == '=') {
-            tokenEnd = pairEnd;
-            foundEqual = true;
+    while (pairEnd < end && cookie[pairEnd] != ';') {
+        if (cookie[pairEnd] == '=') {
+            if (tokenEnd == start) {
+                tokenEnd = pairEnd;
+                foundEqual = true;
+            }
+        } else if (cookie[pairEnd] == '"') {
+            size_t secondQuotePosition = cookie.find('"', pairEnd + 1);
+            if (secondQuotePosition != notFound && secondQuotePosition <= end) {
+                pairEnd = secondQuotePosition + 1;
+                continue;
+            }
         }
-        if (cookie[pairEnd] == '"')
-            quoteFound = !quoteFound;
         pairEnd++;
     }
 
@@ -225,6 +231,15 @@ ParsedCookie* CookieParser::parseOneCookie(const String& cookie, unsigned start,
                 // The path attribute may or may not include percent-encoded characters. Fortunately
                 // if there are no percent-encoded characters, decoding the url is a no-op.
                 res->setPath(decodeURLEscapeSequences(parsedValue));
+
+                // We have to disable the following check because sites like Facebook and
+                // Gmail currently do not follow the spec.
+#if 0
+                // Check if path attribute is a prefix of the request URI.
+                if (!m_defaultCookieURL.path().startsWith(res->path()))
+                    LOG_AND_DELETE("Invalid cookie %s (path): it does not math the URL", cookie.ascii().data());
+#endif
+
             } else
                 LOG_AND_DELETE("Invalid cookie %s (path)", cookie.ascii().data());
             break;
@@ -235,9 +250,33 @@ ParsedCookie* CookieParser::parseOneCookie(const String& cookie, unsigned start,
             if (length >= 6 && cookie.find("omain", tokenStartSvg + 1, false)) {
                 if (parsedValue.length() > 1 && parsedValue[0] == '"' && parsedValue[parsedValue.length() - 1] == '"')
                     parsedValue = parsedValue.substring(1, parsedValue.length() - 2);
+
+                // Check if the domain contains an embedded dot.
+                size_t dotPosition = parsedValue.find(".", 1);
+                if (dotPosition == notFound || dotPosition == parsedValue.length())
+                    LOG_AND_DELETE("Invalid cookie %s (domain): it does not contain an embedded dot", cookie.ascii().data());
+
                 // If the domain does not start with a dot, add one for security checks,
                 // For example: ab.c.com dose not domain match b.c.com;
                 String realDomain = parsedValue[0] == '.' ? parsedValue : "." + parsedValue;
+
+                // The request host should domain match the Domain attribute.
+                // Domain string starts with a dot, so a.b.com should domain match .a.b.com.
+                // add a "." at beginning of host name, because it can handle many cases such as
+                // a.b.com matches b.com, a.b.com matches .B.com and a.b.com matches .A.b.Com
+                // and so on.
+                String hostDomainName = m_defaultCookieURL.host();
+                hostDomainName = hostDomainName.startsWith('.') ? hostDomainName : "." + hostDomainName;
+                if (!hostDomainName.endsWith(realDomain, false))
+                    LOG_AND_DELETE("Invalid cookie %s (domain): it does not domain match the host");
+                // We should check for an embedded dot in the portion of string in the host not in the domain
+                // but to match firefox behaviour we do not.
+
+                // Check whether the domain is a top level domain, if it is throw it out
+                // http://publicsuffix.org/list/
+                if (BlackBerry::Platform::isTopLevelDomain(realDomain.utf8().data()))
+                    LOG_AND_DELETE("Invalid cookie %s (domain): it did not pass the top level domain check", cookie.ascii().data());
+
                 res->setDomain(realDomain);
             } else
                 LOG_AND_DELETE("Invalid cookie %s (domain)", cookie.ascii().data());
@@ -324,7 +363,7 @@ ParsedCookie* CookieParser::parseOneCookie(const String& cookie, unsigned start,
 
     // If no domain was provided, set it to the host
     if (!res->domain())
-        res->setDefaultDomain(m_defaultCookieURL);
+        res->setDomain(m_defaultCookieURL.host());
 
     // According to the Cookie Specificaiton (RFC6265, section 4.1.2.4 and 5.2.4, http://tools.ietf.org/html/rfc6265),
     // If no path was provided or the first character of the path value is not '/', set it to the host's path