[Mac] Optimize cookiesForDOM() by filtering and serializing cookies in a single pass
authorcdumez@apple.com <cdumez@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 20 Oct 2014 07:09:44 +0000 (07:09 +0000)
committercdumez@apple.com <cdumez@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 20 Oct 2014 07:09:44 +0000 (07:09 +0000)
https://bugs.webkit.org/show_bug.cgi?id=137869

Reviewed by Darin Adler.

Optimize cookiesForDOM() by filtering and serializing in 1 pass instead of 2.

Previously, when accessing document.cookie, we ended up doing the following:
1. Call wkHTTPCookiesForURL() to get an NSArray of NSHTTPCookies.
2. Call filterCookies() to filter out cookies that are httpOnly or with an
   empty name, thus allocating a new NSMutableArray.
3. Call NSHTTPCookie's requestHeaderFieldsWithCookies() to serialize the
   cookies
4. Construct a WTF::String from the NSString*

There were several inefficiencies here:
1. We needed to pre-filter the cookies and allocate a new NSMutableArray
   before calling requestHeaderFieldsWithCookies()
2. requestHeaderFieldsWithCookies() does more things that we actually need.
   It constructs a Dictionary of header fields, of which we query the
   "Cookie" field, even though we merely want a ';'-separated string
   representation of the cookies in "key=value" form.

With this patch, we now take care of the string serialization ourselves,
using a StringBuilder as it is trivial to do. This also allows us to filter
out the httpOnly/invalid cookies as we do the serialization instead of
having a first pass to do so.

When scrolling the http://www.apple.com/iphone/ entire page down, then up,
se were spending ~13.1% of the NetworkProcess time in cookiesForDOM()
(~96ms) on my machine. With the patch, we spend ~23% less time in
cookiesForDOM() (~74ms).

No new tests, no behavior change.

* platform/network/mac/CookieJarMac.mm:
(WebCore::cookiesForSession):
(WebCore::cookiesForDOM):
(WebCore::cookieRequestHeaderFieldValue):

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

Source/WebCore/ChangeLog
Source/WebCore/platform/network/mac/CookieJarMac.mm

index eb5aebe..2204456 100644 (file)
@@ -1,3 +1,45 @@
+2014-10-20  Chris Dumez  <cdumez@apple.com>
+
+        [Mac] Optimize cookiesForDOM() by filtering and serializing cookies in a single pass
+        https://bugs.webkit.org/show_bug.cgi?id=137869
+
+        Reviewed by Darin Adler.
+
+        Optimize cookiesForDOM() by filtering and serializing in 1 pass instead of 2.
+
+        Previously, when accessing document.cookie, we ended up doing the following:
+        1. Call wkHTTPCookiesForURL() to get an NSArray of NSHTTPCookies.
+        2. Call filterCookies() to filter out cookies that are httpOnly or with an
+           empty name, thus allocating a new NSMutableArray.
+        3. Call NSHTTPCookie's requestHeaderFieldsWithCookies() to serialize the
+           cookies
+        4. Construct a WTF::String from the NSString*
+
+        There were several inefficiencies here:
+        1. We needed to pre-filter the cookies and allocate a new NSMutableArray
+           before calling requestHeaderFieldsWithCookies()
+        2. requestHeaderFieldsWithCookies() does more things that we actually need.
+           It constructs a Dictionary of header fields, of which we query the
+           "Cookie" field, even though we merely want a ';'-separated string
+           representation of the cookies in "key=value" form.
+
+        With this patch, we now take care of the string serialization ourselves,
+        using a StringBuilder as it is trivial to do. This also allows us to filter
+        out the httpOnly/invalid cookies as we do the serialization instead of
+        having a first pass to do so.
+
+        When scrolling the http://www.apple.com/iphone/ entire page down, then up,
+        se were spending ~13.1% of the NetworkProcess time in cookiesForDOM()
+        (~96ms) on my machine. With the patch, we spend ~23% less time in
+        cookiesForDOM() (~74ms).
+
+        No new tests, no behavior change.
+
+        * platform/network/mac/CookieJarMac.mm:
+        (WebCore::cookiesForSession):
+        (WebCore::cookiesForDOM):
+        (WebCore::cookieRequestHeaderFieldValue):
+
 2014-10-19  Chris Dumez  <cdumez@apple.com>
 
         Kill toRenderedDocumentMarker() by using tighter typing
index 3cd1d2d..eba5569 100644 (file)
@@ -34,6 +34,7 @@
 #import "URL.h"
 #import "NetworkStorageSession.h"
 #import "WebCoreSystemInterface.h"
+#import <wtf/text/StringBuilder.h>
 
 enum {
     NSHTTPCookieAcceptPolicyExclusivelyFromMainDocumentDomain = 3
@@ -69,26 +70,41 @@ static RetainPtr<NSArray> filterCookies(NSArray *unfilteredCookies)
     return filteredCookies;
 }
 
-String cookiesForDOM(const NetworkStorageSession& session, const URL& firstParty, const URL& url)
+enum IncludeHTTPOnlyOrNot { DoNotIncludeHTTPOnly, IncludeHTTPOnly };
+static String cookiesForSession(const NetworkStorageSession& session, const URL& firstParty, const URL& url, IncludeHTTPOnlyOrNot includeHTTPOnly)
 {
     BEGIN_BLOCK_OBJC_EXCEPTIONS;
 
     NSArray *cookies = wkHTTPCookiesForURL(session.cookieStorage().get(), firstParty, url);
-    return [[NSHTTPCookie requestHeaderFieldsWithCookies:filterCookies(cookies).get()] objectForKey:@"Cookie"];
+    StringBuilder cookiesBuilder;
+    for (NSHTTPCookie *cookie in cookies) {
+        if (![[cookie name] length])
+            continue;
+
+        if (!includeHTTPOnly && [cookie isHTTPOnly])
+            continue;
+
+        if (!cookiesBuilder.isEmpty())
+            cookiesBuilder.appendLiteral("; ");
+
+        cookiesBuilder.append(String([cookie name]));
+        cookiesBuilder.append('=');
+        cookiesBuilder.append(String([cookie value]));
+    }
+    return cookiesBuilder.toString();
 
     END_BLOCK_OBJC_EXCEPTIONS;
     return String();
 }
 
-String cookieRequestHeaderFieldValue(const NetworkStorageSession& session, const URL& firstParty, const URL& url)
+String cookiesForDOM(const NetworkStorageSession& session, const URL& firstParty, const URL& url)
 {
-    BEGIN_BLOCK_OBJC_EXCEPTIONS;
-
-    NSArray *cookies = wkHTTPCookiesForURL(session.cookieStorage().get(), firstParty, url);
-    return [[NSHTTPCookie requestHeaderFieldsWithCookies:cookies] objectForKey:@"Cookie"];
+    return cookiesForSession(session, firstParty, url, DoNotIncludeHTTPOnly);
+}
 
-    END_BLOCK_OBJC_EXCEPTIONS;
-    return String();
+String cookieRequestHeaderFieldValue(const NetworkStorageSession& session, const URL& firstParty, const URL& url)
+{
+    return cookiesForSession(session, firstParty, url, IncludeHTTPOnly);
 }
 
 void setCookiesFromDOM(const NetworkStorageSession& session, const URL& firstParty, const URL& url, const String& cookieStr)