1 /* 2 * Copyright (C) 2012 Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include "config.h" 32 #include "ContextFeaturesClientImpl.h" 33 34 #include "WebDocument.h" 35 #include "WebPermissionClient.h" 36 #include "core/dom/Document.h" 37 #include "weborigin/SecurityOrigin.h" 38 39 using namespace WebCore; 40 41 namespace WebKit { 42 43 class ContextFeaturesCache : public Supplement<ScriptExecutionContext> { 44 public: 45 class Entry { 46 public: 47 enum Value { 48 IsEnabled, 49 IsDisabled, 50 NeedsRefresh 51 }; 52 53 Entry() 54 : m_value(NeedsRefresh) 55 , m_defaultValue(false) 56 { } 57 58 bool isEnabled() const 59 { 60 ASSERT(m_value != NeedsRefresh); 61 return m_value == IsEnabled; 62 } 63 64 void set(bool value, bool defaultValue) 65 { 66 m_value = value ? IsEnabled : IsDisabled; 67 m_defaultValue = defaultValue; 68 } 69 70 bool needsRefresh(bool defaultValue) const 71 { 72 return m_value == NeedsRefresh || m_defaultValue != defaultValue; 73 } 74 75 private: 76 Value m_value; 77 bool m_defaultValue; // Needs to be traked as a part of the signature since it can be changed dynamically. 78 }; 79 80 static const char* supplementName(); 81 static ContextFeaturesCache* from(Document*); 82 83 Entry& entryFor(ContextFeatures::FeatureType type) 84 { 85 size_t index = static_cast<size_t>(type); 86 ASSERT_WITH_SECURITY_IMPLICATION(index < ContextFeatures::FeatureTypeSize); 87 return m_entries[index]; 88 } 89 90 void validateAgainst(Document*); 91 92 private: 93 String m_domain; 94 Entry m_entries[ContextFeatures::FeatureTypeSize]; 95 }; 96 97 const char* ContextFeaturesCache::supplementName() 98 { 99 return "ContextFeaturesCache"; 100 } 101 102 ContextFeaturesCache* ContextFeaturesCache::from(Document* document) 103 { 104 ContextFeaturesCache* cache = static_cast<ContextFeaturesCache*>(Supplement<ScriptExecutionContext>::from(document, supplementName())); 105 if (!cache) { 106 cache = new ContextFeaturesCache(); 107 Supplement<ScriptExecutionContext>::provideTo(document, supplementName(), adoptPtr(cache)); 108 } 109 110 return cache; 111 } 112 113 void ContextFeaturesCache::validateAgainst(Document* document) 114 { 115 String currentDomain = document->securityOrigin()->domain(); 116 if (currentDomain == m_domain) 117 return; 118 m_domain = currentDomain; 119 for (size_t i = 0; i < ContextFeatures::FeatureTypeSize; ++i) 120 m_entries[i] = Entry(); 121 } 122 123 bool ContextFeaturesClientImpl::isEnabled(Document* document, ContextFeatures::FeatureType type, bool defaultValue) 124 { 125 ContextFeaturesCache::Entry& cache = ContextFeaturesCache::from(document)->entryFor(type); 126 if (cache.needsRefresh(defaultValue)) 127 cache.set(askIfIsEnabled(document, type, defaultValue), defaultValue); 128 return cache.isEnabled(); 129 } 130 131 void ContextFeaturesClientImpl::urlDidChange(Document* document) 132 { 133 ContextFeaturesCache::from(document)->validateAgainst(document); 134 } 135 136 bool ContextFeaturesClientImpl::askIfIsEnabled(Document* document, ContextFeatures::FeatureType type, bool defaultValue) 137 { 138 if (!m_client) 139 return defaultValue; 140 141 switch (type) { 142 case ContextFeatures::StyleScoped: 143 return m_client->allowWebComponents(WebDocument(document), defaultValue); 144 case ContextFeatures::MutationEvents: 145 return m_client->allowMutationEvents(WebDocument(document), defaultValue); 146 case ContextFeatures::PushState: 147 return m_client->allowPushState(WebDocument(document)); 148 default: 149 return defaultValue; 150 } 151 } 152 153 } // namespace WebKit 154