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 | |
34 | namespace WebCore { |
35 | |
36 | namespace 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 | |
43 | struct 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 | |
88 | struct 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 | |
111 | struct 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 | |
136 | struct 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 | |
170 | private: |
171 | ActionType m_type; |
172 | uint32_t m_actionID; |
173 | String m_stringArgument; |
174 | }; |
175 | |
176 | class ContentExtensionRule { |
177 | public: |
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 | |
192 | private: |
193 | Trigger m_trigger; |
194 | Action m_action; |
195 | }; |
196 | |
197 | } // namespace ContentExtensions |
198 | } // namespace WebCore |
199 | |
200 | #endif // ENABLE(CONTENT_EXTENSIONS) |
201 | |