Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(178)

Side by Side Diff: third_party/WebKit/Source/core/page/FrameTree.cpp

Issue 1968213002: Try harder to make sure that blink::FrameTree::m_uniqueName is truly unique. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: New test, polished the new format a bit, added comments. Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (C) Research In Motion Limited 2010. All rights reserved. 2 * Copyright (C) Research In Motion Limited 2010. All rights reserved.
3 * Copyright (C) 2006 Apple Computer, Inc. 3 * Copyright (C) 2006 Apple Computer, Inc.
4 * 4 *
5 * This library is free software; you can redistribute it and/or 5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public 6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either 7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version. 8 * version 2 of the License, or (at your option) any later version.
9 * 9 *
10 * This library is distributed in the hope that it will be useful, 10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details. 13 * Library General Public License for more details.
14 * 14 *
15 * You should have received a copy of the GNU Library General Public License 15 * You should have received a copy of the GNU Library General Public License
16 * along with this library; see the file COPYING.LIB. If not, write to 16 * along with this library; see the file COPYING.LIB. If not, write to
17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA. 18 * Boston, MA 02110-1301, USA.
19 */ 19 */
20 20
21 #include "core/page/FrameTree.h" 21 #include "core/page/FrameTree.h"
22 22
23 #include "core/dom/Document.h" 23 #include "core/dom/Document.h"
24 #include "core/frame/FrameClient.h" 24 #include "core/frame/FrameClient.h"
25 #include "core/frame/FrameView.h" 25 #include "core/frame/FrameView.h"
26 #include "core/frame/LocalFrame.h" 26 #include "core/frame/LocalFrame.h"
27 #include "core/frame/RemoteFrame.h" 27 #include "core/frame/RemoteFrame.h"
28 #include "core/frame/RemoteFrameView.h" 28 #include "core/frame/RemoteFrameView.h"
29 #include "core/page/Page.h" 29 #include "core/page/Page.h"
30 #include "wtf/Assertions.h"
30 #include "wtf/Vector.h" 31 #include "wtf/Vector.h"
31 #include "wtf/text/CString.h" 32 #include "wtf/text/CString.h"
32 #include "wtf/text/StringBuilder.h" 33 #include "wtf/text/StringBuilder.h"
33 34
34 using std::swap; 35 using std::swap;
35 36
36 namespace blink { 37 namespace blink {
37 38
38 namespace { 39 namespace {
39 40
40 const unsigned invalidChildCount = ~0U; 41 const unsigned invalidChildCount = ~0U;
41 42
42 } // namespace 43 } // namespace
43 44
44 FrameTree::FrameTree(Frame* thisFrame) 45 FrameTree::FrameTree(Frame* thisFrame)
45 : m_thisFrame(thisFrame) 46 : m_thisFrame(thisFrame)
46 , m_scopedChildCount(invalidChildCount) 47 , m_scopedChildCount(invalidChildCount)
47 { 48 {
48 } 49 }
49 50
50 FrameTree::~FrameTree() 51 FrameTree::~FrameTree()
51 { 52 {
52 } 53 }
53 54
54 void FrameTree::setName(const AtomicString& name, const AtomicString& fallbackNa me) 55 void FrameTree::setName(const AtomicString& name)
55 { 56 {
56 m_name = name; 57 m_name = name;
57 if (!parent()) {
58 m_uniqueName = name;
59 return;
60 }
61 58
62 // Remove our old frame name so it's not considered in calculateUniqueNameFo rChildFrame. 59 // Remove our old frame name so it's not considered in calculateUniqueNameFo rChildFrame
60 // and ensureUniquenessOfUniqueName calls below.
63 m_uniqueName = AtomicString(); 61 m_uniqueName = AtomicString();
64 62
65 m_uniqueName = parent()->tree().calculateUniqueNameForChildFrame(true, name, fallbackName); 63 // Calculate a new unique name based on inputs.
64 if (parent()) {
65 setUniqueName(
66 parent()->tree().calculateUniqueNameForChildFrame(m_thisFrame, name, nullAtom));
67 } else if (name.isEmpty() || !uniqueNameExists(name)) {
68 // Only main frame can have an empty unique name, so for main frames
69 // emptiness guarantees uniquness.
70 setUniqueName(name);
71 } else {
72 setUniqueName(ensureUniquenessOfUniqueName(
73 name, "<!--framePosition"));
74 }
66 } 75 }
67 76
68 void FrameTree::setPrecalculatedName(const AtomicString& name, const AtomicStrin g& uniqueName) 77 void FrameTree::setPrecalculatedName(const AtomicString& name, const AtomicStrin g& uniqueName)
69 { 78 {
70 if (!parent()) { 79 if (!parent()) {
71 ASSERT(uniqueName == name); 80 DCHECK(uniqueName == name);
72 } else { 81 } else {
73 ASSERT(!uniqueName.isEmpty()); 82 DCHECK(!uniqueName.isEmpty());
74 } 83 }
75 84
76 m_name = name; 85 m_name = name;
86
87 // TODO(lukasza): We would like to assert uniqueness below (i.e. by calling
88 // setUniqueName), but
89 // 1) uniqueness is currently violated by provisional/old frame pairs.
90 // 2) there is an unresolved race between 2 OOPIFs, that can result in a
91 // non-unique |uniqueName| - see https://crbug.com/558680#c14.
77 m_uniqueName = uniqueName; 92 m_uniqueName = uniqueName;
78 } 93 }
79 94
80 Frame* FrameTree::parent() const 95 Frame* FrameTree::parent() const
81 { 96 {
82 if (!m_thisFrame->client()) 97 if (!m_thisFrame->client())
83 return nullptr; 98 return nullptr;
84 return m_thisFrame->client()->parent(); 99 return m_thisFrame->client()->parent();
85 } 100 }
86 101
(...skipping 29 matching lines...) Expand all
116 return m_thisFrame->client()->firstChild(); 131 return m_thisFrame->client()->firstChild();
117 } 132 }
118 133
119 Frame* FrameTree::lastChild() const 134 Frame* FrameTree::lastChild() const
120 { 135 {
121 if (!m_thisFrame->client()) 136 if (!m_thisFrame->client())
122 return nullptr; 137 return nullptr;
123 return m_thisFrame->client()->lastChild(); 138 return m_thisFrame->client()->lastChild();
124 } 139 }
125 140
126 bool FrameTree::uniqueNameExists(const AtomicString& name) const 141 bool FrameTree::uniqueNameExists(const AtomicString& uniqueNameCandidate) const
127 { 142 {
143 // This method is currently O(N), where N = number of frames in the tree.
144
145 // Before recalculating or checking unique name, we set m_uniqueName
146 // to an empty string (so the soon-to-be-removed name does not count
147 // as a collision). This means that uniqueNameExists would return
148 // false positives when called with an empty |name|.
149 DCHECK(!uniqueNameCandidate.isEmpty());
150
128 for (Frame* frame = top(); frame; frame = frame->tree().traverseNext()) { 151 for (Frame* frame = top(); frame; frame = frame->tree().traverseNext()) {
129 if (frame->tree().uniqueName() == name) 152 if (frame->tree().uniqueName() == uniqueNameCandidate)
130 return true; 153 return true;
131 } 154 }
132 return false; 155 return false;
133 } 156 }
134 157
135 AtomicString FrameTree::calculateUniqueNameForNewChildFrame( 158 AtomicString FrameTree::calculateUniqueNameForNewChildFrame(
136 const AtomicString& name, 159 const AtomicString& name,
137 const AtomicString& fallbackName) const 160 const AtomicString& fallbackName) const
138 { 161 {
139 return calculateUniqueNameForChildFrame(false, name, fallbackName); 162 AtomicString uniqueName = calculateUniqueNameForChildFrame(nullptr, name, fa llbackName);
163
164 // Caller will likely set the name via setPrecalculatedName, which
165 // unfortunately cannot currently assert uniqueness of the name - let's
166 // therefore assert the uniqueness here.
167 DCHECK(!uniqueNameExists(uniqueName));
168
169 return uniqueName;
140 } 170 }
141 171
142 AtomicString FrameTree::calculateUniqueNameForChildFrame( 172 AtomicString FrameTree::generateOldStyleMaybeUniqueName(bool existingChildFrame) const
143 bool existingChildFrame,
144 const AtomicString& name,
145 const AtomicString& fallbackName) const
146 { 173 {
147 const AtomicString& requestedName = name.isEmpty() ? fallbackName : name;
148 if (!requestedName.isEmpty() && !uniqueNameExists(requestedName) && requeste dName != "_blank")
149 return requestedName;
150
151 // Create a repeatable name for a child about to be added to us. The name mu st be
152 // unique within the frame tree. The string we generate includes a "path" of names
153 // from the root frame down to us. For this path to be unique, each set of s iblings must
154 // contribute a unique name to the path, which can't collide with any HTML-a ssigned names.
155 // We generate this path component by index in the child list along with an unlikely
156 // frame name that can't be set in HTML because it collides with comment syn tax.
157
158 const char framePathPrefix[] = "<!--framePath "; 174 const char framePathPrefix[] = "<!--framePath ";
159 const int framePathPrefixLength = 14; 175 const int framePathPrefixLength = 14;
160 const int framePathSuffixLength = 3; 176 const int framePathSuffixLength = 3;
161 177
162 // Find the nearest parent that has a frame with a path in it. 178 // Find the nearest parent that has a frame with a path in it.
163 HeapVector<Member<Frame>, 16> chain; 179 HeapVector<Member<Frame>, 16> chain;
164 Frame* frame; 180 Frame* frame;
165 for (frame = m_thisFrame; frame; frame = frame->tree().parent()) { 181 for (frame = m_thisFrame; frame; frame = frame->tree().parent()) {
166 if (frame->tree().uniqueName().startsWith(framePathPrefix)) 182 if (frame->tree().uniqueName().startsWith(framePathPrefix))
167 break; 183 break;
168 chain.append(frame); 184 chain.append(frame);
169 } 185 }
170 StringBuilder uniqueName; 186 StringBuilder uniqueName;
171 uniqueName.append(framePathPrefix); 187 uniqueName.append(framePathPrefix);
172 if (frame) { 188 if (frame) {
173 uniqueName.append(frame->tree().uniqueName().getString().substring(frame PathPrefixLength, 189 uniqueName.append(frame->tree().uniqueName().getString().substring(frame PathPrefixLength,
174 frame->tree().uniqueName().length() - framePathPrefixLength - frameP athSuffixLength)); 190 frame->tree().uniqueName().length() - framePathPrefixLength - frameP athSuffixLength));
175 } 191 }
176 for (int i = chain.size() - 1; i >= 0; --i) { 192 for (int i = chain.size() - 1; i >= 0; --i) {
177 frame = chain[i]; 193 frame = chain[i];
178 uniqueName.append('/'); 194 uniqueName.append('/');
179 uniqueName.append(frame->tree().uniqueName()); 195 uniqueName.append(frame->tree().uniqueName());
180 } 196 }
181 197
182 uniqueName.appendLiteral("/<!--frame"); 198 uniqueName.appendLiteral("/<!--frame");
183 uniqueName.appendNumber(childCount() - (existingChildFrame ? 1 : 0)); 199 uniqueName.appendNumber(childCount() - (existingChildFrame ? 1 : 0));
184 uniqueName.appendLiteral("-->-->"); 200 uniqueName.appendLiteral("-->-->");
185 201
202 // NOTE: This name might not be unique - see http://crbug.com/588800.
186 return uniqueName.toAtomicString(); 203 return uniqueName.toAtomicString();
187 } 204 }
188 205
206 String FrameTree::generateLikelyUniqueSuffix(Frame* child) const
207 {
208 // This method is currently O(N), where N = number of frames in the tree.
209
210 StringBuilder likelyUniqueSuffixBuilder;
211 likelyUniqueSuffixBuilder.append("<!--framePosition");
212
213 if (!child) {
dcheng 2016/05/31 19:57:47 When will child be null?
Łukasz Anforowicz 2016/05/31 23:50:20 |child| will be null in cases when we need to calc
214 likelyUniqueSuffixBuilder.append('-');
215 likelyUniqueSuffixBuilder.appendNumber(childCount());
216 child = m_thisFrame;
217 }
218
219 while (child->tree().parent()) {
220 int numberOfSiblingsBeforeChild = 0;
221 Frame* sibling = child->tree().previousSibling();
222 while (sibling) {
223 sibling = sibling->tree().previousSibling();
224 numberOfSiblingsBeforeChild++;
225 }
226
227 likelyUniqueSuffixBuilder.append('-');
228 likelyUniqueSuffixBuilder.appendNumber(numberOfSiblingsBeforeChild);
229
230 child = child->tree().parent();
231 }
232
233 // NOTE: The generated suffix is not guaranteed to be unique, but should
234 // have a better chance of being unique than the string generated by
235 // generateOldStyleMaybeUniqueName, because we embed extra information
236 // into the string:
237 // 1) we walk the full chain of ancestors, all the way to the main frame
238 // 2) we use frame-position-within-parent (aka |numberOfSiblingsBeforeChild| )
239 return likelyUniqueSuffixBuilder.toString();
240 }
241
242 AtomicString FrameTree::ensureUniquenessOfUniqueName(
243 const AtomicString& notYetUniqueName,
244 const String& likelyUniqueSuffix) const
245 {
246 // Verify that we are not doing unnecessary work.
247 DCHECK(uniqueNameExists(notYetUniqueName));
248
249 // We want unique name to be stable across page reloads - this is why
250 // we use a deterministic |numberOfTries| rather than a random number
251 // (a random number would be more likely to avoid a collision, but
252 // would change after every page reload).
253 int numberOfTries = 0;
254
255 // Keep trying |notYetUniqueName| + |likelyUniqueSuffix| + |numberOfTries|
256 // concatenations until we get a truly unique name.
257 AtomicString uniqueNameCandidate;
258 do {
259 StringBuilder uniqueNameBuilder;
260 uniqueNameBuilder.append(notYetUniqueName);
261 uniqueNameBuilder.append(likelyUniqueSuffix);
262 uniqueNameBuilder.append('/');
263 uniqueNameBuilder.appendNumber(numberOfTries++);
264 uniqueNameBuilder.append("-->");
265
266 uniqueNameCandidate = uniqueNameBuilder.toAtomicString();
267 } while (uniqueNameExists(uniqueNameCandidate));
268 return uniqueNameCandidate;
269 }
270
271 AtomicString FrameTree::calculateUniqueNameForChildFrame(
272 Frame* child,
273 const AtomicString& assignedName,
274 const AtomicString& fallbackName) const
275 {
276 // Try to use |assignedName| (i.e. window.name or iframe.name) or |fallbackN ame| if possible.
277 const AtomicString& requestedName = assignedName.isEmpty() ? fallbackName : assignedName;
278 if (!requestedName.isEmpty() && !uniqueNameExists(requestedName) && requeste dName != "_blank")
279 return requestedName;
280
281 AtomicString uniqueNameCandidate = generateOldStyleMaybeUniqueName(child);
282 if (!uniqueNameExists(uniqueNameCandidate))
283 return uniqueNameCandidate;
284
285 return ensureUniquenessOfUniqueName(uniqueNameCandidate, generateLikelyUniqu eSuffix(child));
286
287 // Description of the current unique name format
Łukasz Anforowicz 2016/05/27 16:55:27 I am not sure if I am happy with the comment here:
dcheng 2016/05/31 19:57:47 This is fine. It's far better than not having anyt
Łukasz Anforowicz 2016/05/31 23:50:20 Acknowledged.
288 // ---------------------------------------------
289 //
290 // Changing the format of unique name is undesirable, because it breaks
291 // backcompatibility of session history (which stores unique names
292 // generated in the past on user's disk). This incremental,
293 // backcompatibility-aware approach has resulted so far in the following
294 // rather baroque format... :
295 //
296 // uniqueName ::= <assignedName> | <generatedName>
297 // (generatedName is used if assignedName is
298 // 1) non-unique / conflicts with other frame's unique name or
299 // 2) assignedName is empty for a non-main frame)
300 //
301 // assignedName ::= value of iframe's name attribute
302 // or value assigned to window.name
303 //
304 // generatedName ::= oldGeneratedName newUniqueSuffix?
305 // (newUniqueSuffix is only present if oldGeneratedName was
306 // not unique after all)
307 //
308 // oldGeneratedName ::= "<!--framePath //" ancestorChain "/<!--frame" chil dCount "-->-->"
309 // (main frame is special - oldGeneratedName for main frame
310 // is always the frame's assignedName)
311 //
312 // childCount ::= current number of siblings
313 //
314 // ancestorChain ::= concatenated unique names of ancestor chain,
315 // terminated on the first ancestor (if any) starting wi th "<!--framePath"
316 // each ancestor's unique name is separated by "/" chara cter
317 // ancestorChain example1: "grandparent/parent"
318 // (ancestor's unique names : #1--^ | #2-^ )
319 // ancestorChain example2: "<!--framePath //foo/bar/<!--frame42-->-->/blah /foobar"
320 // (ancestor's unique names : ^--#1--^ | #2 | #3-^ )
321 //
322 // newUniqueSuffix ::= "<!--framePosition" framePosition "/" retryNumber " -->"
323 //
324 // framePosition ::= "-" numberOfSiblingsBeforeChild [ framePosition-forPa rent? ]
325 // | <empty string for main frame>
326 //
327 // retryNumber ::= smallest non-negative integer resulting in unique name
328 }
329
330 void FrameTree::setUniqueName(const AtomicString& uniqueName)
331 {
332 // Main frame is the only frame that can have an empty unique name.
333 if (parent()) {
334 DCHECK(!uniqueName.isEmpty() && !uniqueNameExists(uniqueName));
335 } else {
336 DCHECK(uniqueName.isEmpty() || !uniqueNameExists(uniqueName));
337 }
338
339 m_uniqueName = uniqueName;
340 }
341
189 Frame* FrameTree::scopedChild(unsigned index) const 342 Frame* FrameTree::scopedChild(unsigned index) const
190 { 343 {
191 unsigned scopedIndex = 0; 344 unsigned scopedIndex = 0;
192 for (Frame* child = firstChild(); child; child = child->tree().nextSibling() ) { 345 for (Frame* child = firstChild(); child; child = child->tree().nextSibling() ) {
193 if (child->client()->inShadowTree()) 346 if (child->client()->inShadowTree())
194 continue; 347 continue;
195 if (scopedIndex == index) 348 if (scopedIndex == index)
196 return child; 349 return child;
197 scopedIndex++; 350 scopedIndex++;
198 } 351 }
(...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after
422 { 575 {
423 if (!frame) { 576 if (!frame) {
424 printf("Null input frame\n"); 577 printf("Null input frame\n");
425 return; 578 return;
426 } 579 }
427 580
428 printFrames(frame->tree().top(), frame, 0); 581 printFrames(frame->tree().top(), frame, 0);
429 } 582 }
430 583
431 #endif 584 #endif
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698