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

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: Addressed CR comments from dcheng@. 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
« no previous file with comments | « third_party/WebKit/Source/core/page/FrameTree.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 appendUniqueSuffix 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(appendUniqueSuffix(name, "<!--framePosition"));
73 }
66 } 74 }
67 75
68 void FrameTree::setPrecalculatedName(const AtomicString& name, const AtomicStrin g& uniqueName) 76 void FrameTree::setPrecalculatedName(const AtomicString& name, const AtomicStrin g& uniqueName)
69 { 77 {
70 if (!parent()) { 78 if (!parent()) {
71 ASSERT(uniqueName == name); 79 DCHECK(uniqueName == name);
72 } else { 80 } else {
73 ASSERT(!uniqueName.isEmpty()); 81 DCHECK(!uniqueName.isEmpty());
74 } 82 }
75 83
76 m_name = name; 84 m_name = name;
85
86 // TODO(lukasza): We would like to assert uniqueness below (i.e. by calling
87 // setUniqueName), but
88 // 1) uniqueness is currently violated by provisional/old frame pairs.
89 // 2) there is an unresolved race between 2 OOPIFs, that can result in a
90 // non-unique |uniqueName| - see https://crbug.com/558680#c14.
77 m_uniqueName = uniqueName; 91 m_uniqueName = uniqueName;
78 } 92 }
79 93
80 Frame* FrameTree::parent() const 94 Frame* FrameTree::parent() const
81 { 95 {
82 if (!m_thisFrame->client()) 96 if (!m_thisFrame->client())
83 return nullptr; 97 return nullptr;
84 return m_thisFrame->client()->parent(); 98 return m_thisFrame->client()->parent();
85 } 99 }
86 100
(...skipping 29 matching lines...) Expand all
116 return m_thisFrame->client()->firstChild(); 130 return m_thisFrame->client()->firstChild();
117 } 131 }
118 132
119 Frame* FrameTree::lastChild() const 133 Frame* FrameTree::lastChild() const
120 { 134 {
121 if (!m_thisFrame->client()) 135 if (!m_thisFrame->client())
122 return nullptr; 136 return nullptr;
123 return m_thisFrame->client()->lastChild(); 137 return m_thisFrame->client()->lastChild();
124 } 138 }
125 139
126 bool FrameTree::uniqueNameExists(const AtomicString& name) const 140 bool FrameTree::uniqueNameExists(const String& uniqueNameCandidate) const
127 { 141 {
142 // This method is currently O(N), where N = number of frames in the tree.
143
144 // Before recalculating or checking unique name, we set m_uniqueName
145 // to an empty string (so the soon-to-be-removed name does not count
146 // as a collision). This means that uniqueNameExists would return
147 // false positives when called with an empty |name|.
148 DCHECK(!uniqueNameCandidate.isEmpty());
149
128 for (Frame* frame = top(); frame; frame = frame->tree().traverseNext()) { 150 for (Frame* frame = top(); frame; frame = frame->tree().traverseNext()) {
129 if (frame->tree().uniqueName() == name) 151 if (frame->tree().uniqueName() == uniqueNameCandidate)
130 return true; 152 return true;
131 } 153 }
132 return false; 154 return false;
133 } 155 }
134 156
135 AtomicString FrameTree::calculateUniqueNameForNewChildFrame( 157 AtomicString FrameTree::calculateUniqueNameForNewChildFrame(
136 const AtomicString& name, 158 const AtomicString& name,
137 const AtomicString& fallbackName) const 159 const AtomicString& fallbackName) const
138 { 160 {
139 return calculateUniqueNameForChildFrame(false, name, fallbackName); 161 AtomicString uniqueName = calculateUniqueNameForChildFrame(nullptr, name, fa llbackName);
162
163 // Caller will likely set the name via setPrecalculatedName, which
164 // unfortunately cannot currently assert uniqueness of the name - let's
165 // therefore assert the uniqueness here.
166 DCHECK(!uniqueNameExists(uniqueName));
167
168 return uniqueName;
140 } 169 }
141 170
142 AtomicString FrameTree::calculateUniqueNameForChildFrame( 171 String FrameTree::generateUniqueNameCandidate(bool existingChildFrame) const
143 bool existingChildFrame,
144 const AtomicString& name,
145 const AtomicString& fallbackName) const
146 { 172 {
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 "; 173 const char framePathPrefix[] = "<!--framePath ";
159 const int framePathPrefixLength = 14; 174 const int framePathPrefixLength = 14;
160 const int framePathSuffixLength = 3; 175 const int framePathSuffixLength = 3;
161 176
162 // Find the nearest parent that has a frame with a path in it. 177 // Find the nearest parent that has a frame with a path in it.
163 HeapVector<Member<Frame>, 16> chain; 178 HeapVector<Member<Frame>, 16> chain;
164 Frame* frame; 179 Frame* frame;
165 for (frame = m_thisFrame; frame; frame = frame->tree().parent()) { 180 for (frame = m_thisFrame; frame; frame = frame->tree().parent()) {
166 if (frame->tree().uniqueName().startsWith(framePathPrefix)) 181 if (frame->tree().uniqueName().startsWith(framePathPrefix))
167 break; 182 break;
168 chain.append(frame); 183 chain.append(frame);
169 } 184 }
170 StringBuilder uniqueName; 185 StringBuilder uniqueName;
171 uniqueName.append(framePathPrefix); 186 uniqueName.append(framePathPrefix);
172 if (frame) { 187 if (frame) {
173 uniqueName.append(frame->tree().uniqueName().getString().substring(frame PathPrefixLength, 188 uniqueName.append(frame->tree().uniqueName().getString().substring(frame PathPrefixLength,
174 frame->tree().uniqueName().length() - framePathPrefixLength - frameP athSuffixLength)); 189 frame->tree().uniqueName().length() - framePathPrefixLength - frameP athSuffixLength));
175 } 190 }
176 for (int i = chain.size() - 1; i >= 0; --i) { 191 for (int i = chain.size() - 1; i >= 0; --i) {
177 frame = chain[i]; 192 frame = chain[i];
178 uniqueName.append('/'); 193 uniqueName.append('/');
179 uniqueName.append(frame->tree().uniqueName()); 194 uniqueName.append(frame->tree().uniqueName());
180 } 195 }
181 196
182 uniqueName.appendLiteral("/<!--frame"); 197 uniqueName.appendLiteral("/<!--frame");
183 uniqueName.appendNumber(childCount() - (existingChildFrame ? 1 : 0)); 198 uniqueName.appendNumber(childCount() - (existingChildFrame ? 1 : 0));
184 uniqueName.appendLiteral("-->-->"); 199 uniqueName.appendLiteral("-->-->");
185 200
201 // NOTE: This name might not be unique - see http://crbug.com/588800.
186 return uniqueName.toAtomicString(); 202 return uniqueName.toAtomicString();
187 } 203 }
188 204
205 String FrameTree::generateFramePosition(Frame* child) const
206 {
207 // This method is currently O(N), where N = number of frames in the tree.
208
209 StringBuilder framePositionBuilder;
210 framePositionBuilder.append("<!--framePosition");
211
212 if (!child) {
213 framePositionBuilder.append('-');
214 framePositionBuilder.appendNumber(childCount());
215 child = m_thisFrame;
216 }
217
218 while (child->tree().parent()) {
219 int numberOfSiblingsBeforeChild = 0;
220 Frame* sibling = child->tree().previousSibling();
221 while (sibling) {
222 sibling = sibling->tree().previousSibling();
223 numberOfSiblingsBeforeChild++;
224 }
225
226 framePositionBuilder.append('-');
227 framePositionBuilder.appendNumber(numberOfSiblingsBeforeChild);
228
229 child = child->tree().parent();
230 }
231
232 // NOTE: The generated string is not guaranteed to be unique, but should
233 // have a better chance of being unique than the string generated by
234 // generateUniqueNameCandidate, because we embed extra information into the
235 // string:
236 // 1) we walk the full chain of ancestors, all the way to the main frame
237 // 2) we use frame-position-within-parent (aka |numberOfSiblingsBeforeChild| )
238 // instead of sibling-count.
239 return framePositionBuilder.toString();
240 }
241
242 AtomicString FrameTree::appendUniqueSuffix(
243 const String& prefix,
244 const String& likelyUniqueSuffix) const
245 {
246 // Verify that we are not doing unnecessary work.
247 DCHECK(uniqueNameExists(prefix));
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 |prefix| + |likelyUniqueSuffix| + |numberOfTries|
256 // concatenations until we get a truly unique name.
257 String candidate;
258 do {
259 StringBuilder uniqueNameBuilder;
260 uniqueNameBuilder.append(prefix);
261 uniqueNameBuilder.append(likelyUniqueSuffix);
262 uniqueNameBuilder.append('/');
263 uniqueNameBuilder.appendNumber(numberOfTries++);
264 uniqueNameBuilder.append("-->");
265
266 candidate = uniqueNameBuilder.toString();
267 } while (uniqueNameExists(candidate));
268 return AtomicString(candidate);
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 String candidate = generateUniqueNameCandidate(child);
282 if (!uniqueNameExists(candidate))
283 return AtomicString(candidate);
284
285 String likelyUniqueSuffix = generateFramePosition(child);
286 return appendUniqueSuffix(candidate, likelyUniqueSuffix);
287
288 // Description of the current unique name format
289 // ---------------------------------------------
290 //
291 // Changing the format of unique name is undesirable, because it breaks
292 // backcompatibility of session history (which stores unique names
293 // generated in the past on user's disk). This incremental,
294 // backcompatibility-aware approach has resulted so far in the following
295 // rather baroque format... :
296 //
297 // uniqueName ::= <assignedName> | <generatedName>
298 // (generatedName is used if assignedName is
299 // 1) non-unique / conflicts with other frame's unique name or
300 // 2) assignedName is empty for a non-main frame)
301 //
302 // assignedName ::= value of iframe's name attribute
303 // or value assigned to window.name
304 //
305 // generatedName ::= oldGeneratedName newUniqueSuffix?
306 // (newUniqueSuffix is only present if oldGeneratedName was
307 // not unique after all)
308 //
309 // oldGeneratedName ::= "<!--framePath //" ancestorChain "/<!--frame" chil dCount "-->-->"
310 // (main frame is special - oldGeneratedName for main frame
311 // is always the frame's assignedName; oldGeneratedName is
312 // generated by generateUniqueNameCandidate method).
313 //
314 // childCount ::= current number of siblings
315 //
316 // ancestorChain ::= concatenated unique names of ancestor chain,
317 // terminated on the first ancestor (if any) starting wi th "<!--framePath"
318 // each ancestor's unique name is separated by "/" chara cter
319 // ancestorChain example1: "grandparent/parent"
320 // (ancestor's unique names : #1--^ | #2-^ )
321 // ancestorChain example2: "<!--framePath //foo/bar/<!--frame42-->-->/blah /foobar"
322 // (ancestor's unique names : ^--#1--^ | #2 | #3-^ )
323 //
324 // newUniqueSuffix ::= "<!--framePosition" framePosition "/" retryNumber " -->"
325 //
326 // framePosition ::= "-" numberOfSiblingsBeforeChild [ framePosition-forPa rent? ]
327 // | <empty string for main frame>
328 //
329 // retryNumber ::= smallest non-negative integer resulting in unique name
330 }
331
332 void FrameTree::setUniqueName(const AtomicString& uniqueName)
333 {
334 // Main frame is the only frame that can have an empty unique name.
335 if (parent()) {
336 DCHECK(!uniqueName.isEmpty() && !uniqueNameExists(uniqueName));
337 } else {
338 DCHECK(uniqueName.isEmpty() || !uniqueNameExists(uniqueName));
339 }
340
341 m_uniqueName = uniqueName;
342 }
343
189 Frame* FrameTree::scopedChild(unsigned index) const 344 Frame* FrameTree::scopedChild(unsigned index) const
190 { 345 {
191 unsigned scopedIndex = 0; 346 unsigned scopedIndex = 0;
192 for (Frame* child = firstChild(); child; child = child->tree().nextSibling() ) { 347 for (Frame* child = firstChild(); child; child = child->tree().nextSibling() ) {
193 if (child->client()->inShadowTree()) 348 if (child->client()->inShadowTree())
194 continue; 349 continue;
195 if (scopedIndex == index) 350 if (scopedIndex == index)
196 return child; 351 return child;
197 scopedIndex++; 352 scopedIndex++;
198 } 353 }
(...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after
422 { 577 {
423 if (!frame) { 578 if (!frame) {
424 printf("Null input frame\n"); 579 printf("Null input frame\n");
425 return; 580 return;
426 } 581 }
427 582
428 printFrames(frame->tree().top(), frame, 0); 583 printFrames(frame->tree().top(), frame, 0);
429 } 584 }
430 585
431 #endif 586 #endif
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/core/page/FrameTree.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698