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

Side by Side Diff: content/renderer/unique_name_helper.cc

Issue 2714943004: Move unique name generation and tracking into //content. (Closed)
Patch Set: Rebase again. Created 3 years, 9 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 | « content/renderer/unique_name_helper.h ('k') | content/shell/test_runner/BUILD.gn » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "content/renderer/unique_name_helper.h"
6
7 #include <vector>
8
9 #include "base/containers/adapters.h"
10 #include "base/logging.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/string_piece.h"
13 #include "content/renderer/render_frame_impl.h"
14 #include "content/renderer/render_frame_proxy.h"
15 #include "third_party/WebKit/public/web/WebLocalFrame.h"
16
17 namespace content {
18
19 namespace {
20
21 const std::string& UniqueNameForFrame(blink::WebFrame* frame) {
22 return frame->isWebLocalFrame()
23 ? RenderFrameImpl::FromWebFrame(frame)->unique_name()
24 : RenderFrameProxy::FromWebFrame(frame)->unique_name();
25 }
26
27 bool UniqueNameExists(blink::WebFrame* top, const std::string& candidate) {
28 // This method is currently O(N), where N = number of frames in the tree.
29
30 // Before recalculating or checking unique name, we set m_uniqueName
31 // to an empty string (so the soon-to-be-removed name does not count
32 // as a collision). This means that uniqueNameExists would return
33 // false positives when called with an empty |name|.
34 DCHECK(!candidate.empty());
35
36 for (blink::WebFrame* frame = top; frame; frame = frame->traverseNext()) {
37 if (UniqueNameForFrame(frame) == candidate)
38 return true;
39 }
40
41 return false;
42 }
43
44 std::string GenerateCandidate(blink::WebFrame* parent, blink::WebFrame* child) {
45 constexpr char kFramePathPrefix[] = "<!--framePath ";
46 constexpr int kFramePathPrefixLength = 14;
47 constexpr int kFramePathSuffixLength = 3;
48
49 std::string new_name(kFramePathPrefix);
50
51 // Find the nearest parent that has a frame with a path in it.
52 std::vector<blink::WebFrame*> chain;
53 for (blink::WebFrame* frame = parent; frame; frame = frame->parent()) {
54 base::StringPiece name = UniqueNameForFrame(frame);
55 if (name.starts_with(kFramePathPrefix) && name.ends_with("-->") &&
56 kFramePathPrefixLength + kFramePathSuffixLength < name.size()) {
57 name.substr(kFramePathPrefixLength,
58 name.size() - kFramePathPrefixLength - kFramePathSuffixLength)
59 .AppendToString(&new_name);
60 break;
61 }
62 chain.push_back(frame);
63 }
64
65 for (auto* frame : base::Reversed(chain)) {
66 new_name += '/';
67 new_name += UniqueNameForFrame(frame);
68 }
69
70 int child_count = 0;
71 for (blink::WebFrame* frame = parent->firstChild(); frame;
72 frame = frame->nextSibling()) {
73 ++child_count;
74 }
75
76 // When generating a candidate, a null |child| means that this is the
77 // candidate name for a child frame that's not yet attached.
78 new_name += "/<!--frame";
79 new_name += base::IntToString(child_count - (child ? 1 : 0));
80 new_name += "-->-->";
81
82 // NOTE: This name might not be unique - see http://crbug.com/588800.
83 return new_name;
84 }
85
86 std::string GenerateFramePosition(blink::WebFrame* parent,
87 blink::WebFrame* child) {
88 // This method is currently O(N), where N = number of frames in the tree.
89
90 std::string position_string("<!--framePosition");
91
92 while (parent) {
93 int position_in_parent = 0;
94 blink::WebFrame* sibling = parent->firstChild();
95 while (sibling != child) {
96 sibling = sibling->nextSibling();
97 ++position_in_parent;
98 }
99
100 position_string += '-';
101 position_string += base::IntToString(position_in_parent);
102
103 child = parent;
104 parent = parent->parent();
105 }
106
107 // NOTE: The generated string is not guaranteed to be unique, but should
108 // have a better chance of being unique than the string generated by
109 // GenerateCandidate, because we embed extra information into the string:
110 // 1) we walk the full chain of ancestors, all the way to the main frame
111 // 2) we use frame-position-within-parent (aka |position_in_parent|)
112 // instead of sibling-count.
113 return position_string;
114 }
115
116 std::string AppendUniqueSuffix(blink::WebFrame* top,
117 const std::string& prefix,
118 const std::string& likely_unique_suffix) {
119 // This should only be called if the |prefix| isn't unique, as this is
120 // otherwise pointless work.
121 DCHECK(UniqueNameExists(top, prefix));
122
123 // We want unique name to be stable across page reloads - this is why
124 // we use a deterministic |number_of_tries| rather than a random number
125 // (a random number would be more likely to avoid a collision, but
126 // would change after every page reload).
127 int number_of_retries = 0;
128
129 // Keep trying |prefix| + |likely_unique_suffix| + |number_of_tries|
130 // concatenations until we get a truly unique name.
131 std::string candidate(prefix);
132 candidate += likely_unique_suffix;
133 candidate += '/';
134 while (true) {
135 size_t current_length = candidate.size();
136 candidate += base::IntToString(number_of_retries++);
137 candidate += "-->";
138 if (!UniqueNameExists(top, candidate))
139 break;
140 candidate.resize(current_length);
141 }
142 return candidate;
143 }
144
145 std::string CalculateNewName(blink::WebFrame* parent,
146 blink::WebFrame* child,
147 const std::string& name) {
148 blink::WebFrame* top = parent->top();
149 if (!name.empty() && !UniqueNameExists(top, name) && name != "_blank")
150 return name;
151
152 std::string candidate = GenerateCandidate(parent, child);
153 if (!UniqueNameExists(top, candidate))
154 return candidate;
155
156 std::string likely_unique_suffix = GenerateFramePosition(parent, child);
157 return AppendUniqueSuffix(top, candidate, likely_unique_suffix);
158 }
159
160 } // namespace
161
162 UniqueNameHelper::UniqueNameHelper(RenderFrameImpl* render_frame)
163 : render_frame_(render_frame) {}
164
165 UniqueNameHelper::~UniqueNameHelper() {}
166
167 std::string UniqueNameHelper::GenerateNameForNewChildFrame(
168 blink::WebFrame* parent,
169 const std::string& name) {
170 return CalculateNewName(parent, nullptr, name);
171 }
172
173 void UniqueNameHelper::UpdateName(const std::string& name) {
174 // The unique name of the main frame is always the empty string.
175 if (!GetWebFrame()->parent())
176 return;
177 // It's important to clear this before calculating a new name, as the
178 // calculation checks for collisions with existing unique names.
179 unique_name_.clear();
180 unique_name_ = CalculateNewName(GetWebFrame()->parent(), GetWebFrame(), name);
181 }
182
183 blink::WebLocalFrame* UniqueNameHelper::GetWebFrame() const {
184 return render_frame_->GetWebFrame();
185 }
186
187 } // namespace content
OLDNEW
« no previous file with comments | « content/renderer/unique_name_helper.h ('k') | content/shell/test_runner/BUILD.gn » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698