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 "web/ContextFeaturesClientImpl.h" 33 34#include "core/dom/Document.h" 35#include "platform/weborigin/SecurityOrigin.h" 36#include "public/web/WebDocument.h" 37#include "public/web/WebPermissionClient.h" 38#include "web/WebLocalFrameImpl.h" 39 40namespace blink { 41 42class ContextFeaturesCache FINAL : public NoBaseWillBeGarbageCollectedFinalized<ContextFeaturesCache>, public DocumentSupplement { 43 WILL_BE_USING_GARBAGE_COLLECTED_MIXIN(ContextFeaturesCache); 44public: 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 92private: 93 String m_domain; 94 Entry m_entries[ContextFeatures::FeatureTypeSize]; 95}; 96 97const char* ContextFeaturesCache::supplementName() 98{ 99 return "ContextFeaturesCache"; 100} 101 102ContextFeaturesCache& ContextFeaturesCache::from(Document& document) 103{ 104 ContextFeaturesCache* cache = static_cast<ContextFeaturesCache*>(DocumentSupplement::from(document, supplementName())); 105 if (!cache) { 106 cache = new ContextFeaturesCache(); 107 DocumentSupplement::provideTo(document, supplementName(), adoptPtrWillBeNoop(cache)); 108 } 109 110 return *cache; 111} 112 113void 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 123bool ContextFeaturesClientImpl::isEnabled(Document* document, ContextFeatures::FeatureType type, bool defaultValue) 124{ 125 ASSERT(document); 126 ContextFeaturesCache::Entry& cache = ContextFeaturesCache::from(*document).entryFor(type); 127 if (cache.needsRefresh(defaultValue)) 128 cache.set(askIfIsEnabled(document, type, defaultValue), defaultValue); 129 return cache.isEnabled(); 130} 131 132void ContextFeaturesClientImpl::urlDidChange(Document* document) 133{ 134 ASSERT(document); 135 ContextFeaturesCache::from(*document).validateAgainst(document); 136} 137 138bool ContextFeaturesClientImpl::askIfIsEnabled(Document* document, ContextFeatures::FeatureType type, bool defaultValue) 139{ 140 WebLocalFrameImpl* frame = WebLocalFrameImpl::fromFrame(document->frame()); 141 if (!frame || !frame->permissionClient()) 142 return defaultValue; 143 144 switch (type) { 145 case ContextFeatures::MutationEvents: 146 return frame->permissionClient()->allowMutationEvents(defaultValue); 147 case ContextFeatures::PushState: 148 return frame->permissionClient()->allowPushState(); 149 default: 150 return defaultValue; 151 } 152} 153 154} // namespace blink 155