1/*
2 * Copyright (C) 2014, 2015 Apple 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
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#pragma once
27
28#if ENABLE(CONTENT_EXTENSIONS)
29
30#include "ContentExtensionActions.h"
31#include "ResourceLoadInfo.h"
32#include <wtf/text/WTFString.h>
33
34namespace WebCore {
35
36namespace ContentExtensions {
37
38// A ContentExtensionRule is the smallest unit in a ContentExtension.
39//
40// It is composed of a trigger and an action. The trigger defines on what kind of content this extension should apply.
41// The action defines what to perform on that content.
42
43struct Trigger {
44 String urlFilter;
45 bool urlFilterIsCaseSensitive { false };
46 bool topURLConditionIsCaseSensitive { false };
47 ResourceFlags flags { 0 };
48 Vector<String> conditions;
49 enum class ConditionType {
50 None,
51 IfDomain,
52 UnlessDomain,
53 IfTopURL,
54 UnlessTopURL,
55 };
56 ConditionType conditionType { ConditionType::None };
57
58 WEBCORE_EXPORT Trigger isolatedCopy() const;
59
60 ~Trigger()
61 {
62 ASSERT(conditions.isEmpty() == (conditionType == ConditionType::None));
63 if (topURLConditionIsCaseSensitive)
64 ASSERT(conditionType == ConditionType::IfTopURL || conditionType == ConditionType::UnlessTopURL);
65 }
66
67 bool isEmpty() const
68 {
69 return urlFilter.isEmpty()
70 && !urlFilterIsCaseSensitive
71 && !topURLConditionIsCaseSensitive
72 && !flags
73 && conditions.isEmpty()
74 && conditionType == ConditionType::None;
75 }
76
77 bool operator==(const Trigger& other) const
78 {
79 return urlFilter == other.urlFilter
80 && urlFilterIsCaseSensitive == other.urlFilterIsCaseSensitive
81 && topURLConditionIsCaseSensitive == other.topURLConditionIsCaseSensitive
82 && flags == other.flags
83 && conditions == other.conditions
84 && conditionType == other.conditionType;
85 }
86};
87
88struct TriggerHash {
89 static unsigned hash(const Trigger& trigger)
90 {
91 unsigned hash = trigger.urlFilterIsCaseSensitive ? 10619863 : 40960001;
92 if (!trigger.urlFilter.isNull())
93 hash ^= StringHash::hash(trigger.urlFilter);
94 hash = WTF::pairIntHash(hash, DefaultHash<ResourceFlags>::Hash::hash(trigger.flags));
95
96 for (const String& condition : trigger.conditions)
97 hash ^= StringHash::hash(condition);
98
99 hash ^= 1 << static_cast<unsigned>(trigger.conditionType);
100 return hash;
101 }
102
103 static bool equal(const Trigger& a, const Trigger& b)
104 {
105 return a == b;
106 }
107
108 static const bool safeToCompareToEmptyOrDeleted = false;
109};
110
111struct TriggerHashTraits : public WTF::CustomHashTraits<Trigger> {
112 static const bool emptyValueIsZero = false;
113 static const bool hasIsEmptyValueFunction = true;
114
115 static void constructDeletedValue(Trigger& trigger)
116 {
117 new (NotNull, std::addressof(trigger.urlFilter)) String(WTF::HashTableDeletedValue);
118 }
119
120 static bool isDeletedValue(const Trigger& trigger)
121 {
122 return trigger.urlFilter.isHashTableDeletedValue();
123 }
124
125 static Trigger emptyValue()
126 {
127 return Trigger();
128 }
129
130 static bool isEmptyValue(const Trigger& trigger)
131 {
132 return trigger.isEmpty();
133 }
134};
135
136struct Action {
137 Action(ActionType type, const String& stringArgument, uint32_t actionID = std::numeric_limits<uint32_t>::max())
138 : m_type(type)
139 , m_actionID(actionID)
140 , m_stringArgument(stringArgument)
141 {
142 ASSERT(hasStringArgument(type));
143 }
144
145 Action(ActionType type, uint32_t actionID = std::numeric_limits<uint32_t>::max())
146 : m_type(type)
147 , m_actionID(actionID)
148 {
149 ASSERT(!hasStringArgument(type));
150 }
151 Action(Action&&) = default;
152
153 bool operator==(const Action& other) const
154 {
155 return m_type == other.m_type
156 && m_actionID == other.m_actionID
157 && m_stringArgument == other.m_stringArgument;
158 }
159
160 static Action deserialize(const SerializedActionByte* actions, const uint32_t actionsLength, uint32_t location);
161 static ActionType deserializeType(const SerializedActionByte* actions, const uint32_t actionsLength, uint32_t location);
162 static uint32_t serializedLength(const SerializedActionByte* actions, const uint32_t actionsLength, uint32_t location);
163
164 ActionType type() const { return m_type; }
165 uint32_t actionID() const { return m_actionID; }
166 const String& stringArgument() const { return m_stringArgument; }
167
168 WEBCORE_EXPORT Action isolatedCopy() const;
169
170private:
171 ActionType m_type;
172 uint32_t m_actionID;
173 String m_stringArgument;
174};
175
176class ContentExtensionRule {
177public:
178 WEBCORE_EXPORT ContentExtensionRule(Trigger&&, Action&&);
179
180 const Trigger& trigger() const { return m_trigger; }
181 const Action& action() const { return m_action; }
182
183 ContentExtensionRule isolatedCopy() const
184 {
185 return { m_trigger.isolatedCopy(), m_action.isolatedCopy() };
186 }
187 bool operator==(const ContentExtensionRule& other) const
188 {
189 return m_trigger == other.m_trigger && m_action == other.m_action;
190 }
191
192private:
193 Trigger m_trigger;
194 Action m_action;
195};
196
197} // namespace ContentExtensions
198} // namespace WebCore
199
200#endif // ENABLE(CONTENT_EXTENSIONS)
201