Source/WebCore/ChangeLog

 12014-02-06 Anders Carlsson <andersca@apple.com>
 2
 3 Modernize CrossOriginPreflightResultCache
 4 https://bugs.webkit.org/show_bug.cgi?id=128309
 5
 6 Reviewed by NOBODY (OOPS!).
 7
 8 Use std::chrono::steady_clock instead of currentTime() for determining when
 9 cache items expire, Use std::unique_ptr instead of OwnPtr, use NeverDestroyed,
 10 get rid of unnecessary container typedefs now that we have auto. Finally,
 11 de-indent the entire class declaration.
 12
 13 * loader/CrossOriginPreflightResultCache.cpp:
 14 (WebCore::CrossOriginPreflightResultCache::CrossOriginPreflightResultCache):
 15 (WebCore::parseAccessControlMaxAge):
 16 (WebCore::CrossOriginPreflightResultCacheItem::parse):
 17 (WebCore::CrossOriginPreflightResultCacheItem::allowsRequest):
 18 (WebCore::CrossOriginPreflightResultCache::shared):
 19 (WebCore::CrossOriginPreflightResultCache::appendEntry):
 20 (WebCore::CrossOriginPreflightResultCache::canSkipPreflight):
 21 * loader/CrossOriginPreflightResultCache.h:
 22 (WebCore::CrossOriginPreflightResultCacheItem::CrossOriginPreflightResultCacheItem):
 23 * loader/DocumentThreadableLoader.cpp:
 24 (WebCore::DocumentThreadableLoader::didReceiveResponse):
 25
1262014-02-06 Koop Mast <kwm@FreeBSD.org>
227
328 Use system default compiler instead of gcc, as final fall through.

Source/WebCore/loader/CrossOriginPreflightResultCache.cpp

2929
3030#include "CrossOriginAccessControl.h"
3131#include "ResourceResponse.h"
32 #include <wtf/CurrentTime.h>
3332#include <wtf/MainThread.h>
 33#include <wtf/NeverDestroyed.h>
3434#include <wtf/StdLibExtras.h>
3535
3636namespace WebCore {
3737
3838// These values are at the discretion of the user agent.
39 static const unsigned defaultPreflightCacheTimeoutSeconds = 5;
40 static const unsigned maxPreflightCacheTimeoutSeconds = 600; // Should be short enough to minimize the risk of using a poisoned cache after switching to a secure network.
 39static const auto defaultPreflightCacheTimeout = std::chrono::seconds(5);
 40static const auto maxPreflightCacheTimeout = std::chrono::seconds(600); // Should be short enough to minimize the risk of using a poisoned cache after switching to a secure network.
4141
42 static bool parseAccessControlMaxAge(const String& string, unsigned& expiryDelta)
 42CrossOriginPreflightResultCache::CrossOriginPreflightResultCache()
 43{
 44}
 45
 46static bool parseAccessControlMaxAge(const String& string, std::chrono::seconds& expiryDelta)
4347{
4448 // FIXME: this will not do the correct thing for a number starting with a '+'
4549 bool ok = false;
46  expiryDelta = string.toUIntStrict(&ok);
 50 expiryDelta = std::chrono::seconds(string.toUIntStrict(&ok));
4751 return ok;
4852}
4953

@@bool CrossOriginPreflightResultCacheItem::parse(const ResourceResponse& response
99103 return false;
100104 }
101105
102  unsigned expiryDelta;
 106 std::chrono::seconds expiryDelta;
103107 if (parseAccessControlMaxAge(response.httpHeaderField("Access-Control-Max-Age"), expiryDelta)) {
104  if (expiryDelta > maxPreflightCacheTimeoutSeconds)
105  expiryDelta = maxPreflightCacheTimeoutSeconds;
 108 if (expiryDelta > maxPreflightCacheTimeout)
 109 expiryDelta = maxPreflightCacheTimeout;
106110 } else
107  expiryDelta = defaultPreflightCacheTimeoutSeconds;
 111 expiryDelta = defaultPreflightCacheTimeout;
108112
109  m_absoluteExpiryTime = monotonicallyIncreasingTime() + expiryDelta;
 113 m_absoluteExpiryTime = std::chrono::steady_clock::now() + expiryDelta;
110114 return true;
111115}
112116

@@bool CrossOriginPreflightResultCacheItem::allowsCrossOriginHeaders(const HTTPHea
133137bool CrossOriginPreflightResultCacheItem::allowsRequest(StoredCredentials includeCredentials, const String& method, const HTTPHeaderMap& requestHeaders) const
134138{
135139 String ignoredExplanation;
136  if (m_absoluteExpiryTime < monotonicallyIncreasingTime())
 140 if (m_absoluteExpiryTime < std::chrono::steady_clock::now())
137141 return false;
138142 if (includeCredentials == AllowStoredCredentials && m_credentials == DoNotAllowStoredCredentials)
139143 return false;

@@bool CrossOriginPreflightResultCacheItem::allowsRequest(StoredCredentials includ
146150
147151CrossOriginPreflightResultCache& CrossOriginPreflightResultCache::shared()
148152{
149  DEFINE_STATIC_LOCAL(CrossOriginPreflightResultCache, cache, ());
150153 ASSERT(isMainThread());
 154
 155 static NeverDestroyed<CrossOriginPreflightResultCache> cache;
151156 return cache;
152157}
153158
154 void CrossOriginPreflightResultCache::appendEntry(const String& origin, const URL& url, PassOwnPtr<CrossOriginPreflightResultCacheItem> preflightResult)
 159void CrossOriginPreflightResultCache::appendEntry(const String& origin, const URL& url, std::unique_ptr<CrossOriginPreflightResultCacheItem> preflightResult)
155160{
156161 ASSERT(isMainThread());
157  m_preflightHashMap.set(std::make_pair(origin, url), preflightResult);
 162 m_preflightHashMap.set(std::make_pair(origin, url), std::move(preflightResult));
158163}
159164
160165bool CrossOriginPreflightResultCache::canSkipPreflight(const String& origin, const URL& url, StoredCredentials includeCredentials, const String& method, const HTTPHeaderMap& requestHeaders)
161166{
162167 ASSERT(isMainThread());
163  CrossOriginPreflightResultHashMap::iterator cacheIt = m_preflightHashMap.find(std::make_pair(origin, url));
164  if (cacheIt == m_preflightHashMap.end())
 168 auto it = m_preflightHashMap.find(std::make_pair(origin, url));
 169 if (it == m_preflightHashMap.end())
165170 return false;
166171
167  if (cacheIt->value->allowsRequest(includeCredentials, method, requestHeaders))
 172 if (it->value->allowsRequest(includeCredentials, method, requestHeaders))
168173 return true;
169174
170  m_preflightHashMap.remove(cacheIt);
 175 m_preflightHashMap.remove(it);
171176 return false;
172177}
173178

Source/WebCore/loader/CrossOriginPreflightResultCache.h

2929
3030#include "URLHash.h"
3131#include "ResourceHandleTypes.h"
 32#include <chrono>
3233#include <wtf/HashMap.h>
3334#include <wtf/HashSet.h>
34 #include <wtf/PassOwnPtr.h>
3535#include <wtf/text/StringHash.h>
3636
3737namespace WebCore {
3838
39  class HTTPHeaderMap;
40  class ResourceResponse;
41 
42  class CrossOriginPreflightResultCacheItem {
43  WTF_MAKE_NONCOPYABLE(CrossOriginPreflightResultCacheItem); WTF_MAKE_FAST_ALLOCATED;
44  public:
45  CrossOriginPreflightResultCacheItem(StoredCredentials credentials)
46  : m_absoluteExpiryTime(0)
47  , m_credentials(credentials)
48  {
49  }
50 
51  bool parse(const ResourceResponse&, String& errorDescription);
52  bool allowsCrossOriginMethod(const String&, String& errorDescription) const;
53  bool allowsCrossOriginHeaders(const HTTPHeaderMap&, String& errorDescription) const;
54  bool allowsRequest(StoredCredentials, const String& method, const HTTPHeaderMap& requestHeaders) const;
55 
56  private:
57  typedef HashSet<String, CaseFoldingHash> HeadersSet;
58 
59  // FIXME: A better solution to holding onto the absolute expiration time might be
60  // to start a timer for the expiration delta that removes this from the cache when
61  // it fires.
62  double m_absoluteExpiryTime;
63  StoredCredentials m_credentials;
64  HashSet<String> m_methods;
65  HeadersSet m_headers;
66  };
67 
68  class CrossOriginPreflightResultCache {
69  WTF_MAKE_NONCOPYABLE(CrossOriginPreflightResultCache); WTF_MAKE_FAST_ALLOCATED;
70  public:
71  static CrossOriginPreflightResultCache& shared();
72 
73  void appendEntry(const String& origin, const URL&, PassOwnPtr<CrossOriginPreflightResultCacheItem>);
74  bool canSkipPreflight(const String& origin, const URL&, StoredCredentials, const String& method, const HTTPHeaderMap& requestHeaders);
75 
76  void empty();
77 
78  private:
79  CrossOriginPreflightResultCache() { }
80 
81  typedef HashMap<std::pair<String, URL>, OwnPtr<CrossOriginPreflightResultCacheItem>> CrossOriginPreflightResultHashMap;
82 
83  CrossOriginPreflightResultHashMap m_preflightHashMap;
84  };
 39class HTTPHeaderMap;
 40class ResourceResponse;
 41
 42class CrossOriginPreflightResultCacheItem {
 43 WTF_MAKE_NONCOPYABLE(CrossOriginPreflightResultCacheItem); WTF_MAKE_FAST_ALLOCATED;
 44public:
 45 explicit CrossOriginPreflightResultCacheItem(StoredCredentials credentials)
 46 : m_credentials(credentials)
 47 {
 48 }
 49
 50 bool parse(const ResourceResponse&, String& errorDescription);
 51 bool allowsCrossOriginMethod(const String&, String& errorDescription) const;
 52 bool allowsCrossOriginHeaders(const HTTPHeaderMap&, String& errorDescription) const;
 53 bool allowsRequest(StoredCredentials, const String& method, const HTTPHeaderMap& requestHeaders) const;
 54
 55private:
 56 // FIXME: A better solution to holding onto the absolute expiration time might be
 57 // to start a timer for the expiration delta that removes this from the cache when
 58 // it fires.
 59 std::chrono::steady_clock::time_point m_absoluteExpiryTime;
 60 StoredCredentials m_credentials;
 61 HashSet<String> m_methods;
 62 HashSet<String, CaseFoldingHash> m_headers;
 63};
 64
 65class CrossOriginPreflightResultCache {
 66 WTF_MAKE_NONCOPYABLE(CrossOriginPreflightResultCache); WTF_MAKE_FAST_ALLOCATED;
 67
 68public:
 69 static CrossOriginPreflightResultCache& shared();
 70
 71 void appendEntry(const String& origin, const URL&, std::unique_ptr<CrossOriginPreflightResultCacheItem>);
 72 bool canSkipPreflight(const String& origin, const URL&, StoredCredentials, const String& method, const HTTPHeaderMap& requestHeaders);
 73
 74 void empty();
 75
 76private:
 77 friend NeverDestroyed<CrossOriginPreflightResultCache>;
 78 CrossOriginPreflightResultCache();
 79
 80 HashMap<std::pair<String, URL>, std::unique_ptr<CrossOriginPreflightResultCacheItem>> m_preflightHashMap;
 81};
8582
8683} // namespace WebCore
8784

Source/WebCore/loader/DocumentThreadableLoader.cpp

@@void DocumentThreadableLoader::didReceiveResponse(unsigned long identifier, cons
258258 return;
259259 }
260260
261  OwnPtr<CrossOriginPreflightResultCacheItem> preflightResult = adoptPtr(new CrossOriginPreflightResultCacheItem(m_options.allowCredentials));
 261 auto preflightResult = std::make_unique<CrossOriginPreflightResultCacheItem>(static_cast<StoredCredentials>(m_options.allowCredentials));
262262 if (!preflightResult->parse(response, accessControlErrorDescription)
263263 || !preflightResult->allowsCrossOriginMethod(m_actualRequest->httpMethod(), accessControlErrorDescription)
264264 || !preflightResult->allowsCrossOriginHeaders(m_actualRequest->httpHeaderFields(), accessControlErrorDescription)) {

@@void DocumentThreadableLoader::didReceiveResponse(unsigned long identifier, cons
266266 return;
267267 }
268268
269  CrossOriginPreflightResultCache::shared().appendEntry(securityOrigin()->toString(), m_actualRequest->url(), preflightResult.release());
 269 CrossOriginPreflightResultCache::shared().appendEntry(securityOrigin()->toString(), m_actualRequest->url(), std::move(preflightResult));
270270 } else {
271271 if (!m_sameOriginRequest && m_options.crossOriginRequestPolicy == UseAccessControl) {
272272 if (!passesAccessControlCheck(response, m_options.allowCredentials, securityOrigin(), accessControlErrorDescription)) {