| Index: content/renderer/unique_name_helper.cc
|
| diff --git a/content/renderer/unique_name_helper.cc b/content/renderer/unique_name_helper.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..81c8f030f7f67b7226843f2aa6956c9cc8b9b428
|
| --- /dev/null
|
| +++ b/content/renderer/unique_name_helper.cc
|
| @@ -0,0 +1,183 @@
|
| +// Copyright 2017 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "content/renderer/unique_name_helper.h"
|
| +
|
| +#include <vector>
|
| +
|
| +#include "base/containers/adapters.h"
|
| +#include "base/logging.h"
|
| +#include "base/strings/string_number_conversions.h"
|
| +#include "base/strings/string_piece.h"
|
| +#include "content/renderer/render_frame_impl.h"
|
| +#include "content/renderer/render_frame_proxy.h"
|
| +#include "third_party/WebKit/public/web/WebLocalFrame.h"
|
| +
|
| +namespace content {
|
| +
|
| +namespace {
|
| +
|
| +const std::string& UniqueNameForFrame(blink::WebFrame* frame) {
|
| + return frame->isWebLocalFrame()
|
| + ? RenderFrameImpl::FromWebFrame(frame)->unique_name()
|
| + : RenderFrameProxy::FromWebFrame(frame)->unique_name();
|
| +}
|
| +
|
| +bool UniqueNameExists(blink::WebFrame* top, const std::string& candidate) {
|
| + // This method is currently O(N), where N = number of frames in the tree.
|
| +
|
| + // Before recalculating or checking unique name, we set m_uniqueName
|
| + // to an empty string (so the soon-to-be-removed name does not count
|
| + // as a collision). This means that uniqueNameExists would return
|
| + // false positives when called with an empty |name|.
|
| + DCHECK(!candidate.empty());
|
| +
|
| + for (blink::WebFrame* frame = top; frame; frame = frame->traverseNext()) {
|
| + if (UniqueNameForFrame(frame) == candidate)
|
| + return true;
|
| + }
|
| +
|
| + return false;
|
| +}
|
| +
|
| +std::string GenerateCandidate(blink::WebFrame* parent, blink::WebFrame* child) {
|
| + constexpr char kFramePathPrefix[] = "<!--framePath ";
|
| + constexpr int kFramePathPrefixLength = 14;
|
| + constexpr int kFramePathSuffixLength = 3;
|
| +
|
| + std::string new_name(kFramePathPrefix);
|
| +
|
| + // Find the nearest parent that has a frame with a path in it.
|
| + std::vector<blink::WebFrame*> chain;
|
| + for (blink::WebFrame* frame = parent; frame; frame = frame->parent()) {
|
| + base::StringPiece name = UniqueNameForFrame(frame);
|
| + if (name.starts_with(kFramePathPrefix) && name.ends_with("-->") &&
|
| + kFramePathPrefixLength + kFramePathSuffixLength < name.size()) {
|
| + name.substr(kFramePathPrefixLength,
|
| + name.size() - kFramePathPrefixLength - kFramePathSuffixLength)
|
| + .AppendToString(&new_name);
|
| + break;
|
| + }
|
| + chain.push_back(frame);
|
| + }
|
| +
|
| + for (auto* frame : base::Reversed(chain)) {
|
| + new_name += '/';
|
| + new_name += UniqueNameForFrame(frame);
|
| + }
|
| +
|
| + int child_count = 0;
|
| + for (blink::WebFrame* frame = parent->firstChild(); frame != nullptr;
|
| + frame = frame->nextSibling()) {
|
| + ++child_count;
|
| + }
|
| +
|
| + // When generating a candidate, a null |child| means that this is the
|
| + // candidate name for a child frame that's not yet attached.
|
| + new_name += "/<!--frame";
|
| + new_name += base::IntToString(child_count - (child ? 1 : 0));
|
| + new_name += "-->-->";
|
| +
|
| + // NOTE: This name might not be unique - see http://crbug.com/588800.
|
| + return new_name;
|
| +}
|
| +
|
| +std::string GenerateFramePosition(blink::WebFrame* parent,
|
| + blink::WebFrame* child) {
|
| + // This method is currently O(N), where N = number of frames in the tree.
|
| +
|
| + std::string position_string("<!--framePosition");
|
| +
|
| + while (parent) {
|
| + int position_in_parent = 0;
|
| + blink::WebFrame* sibling = parent->firstChild();
|
| + while (sibling != child) {
|
| + sibling = sibling->nextSibling();
|
| + ++position_in_parent;
|
| + }
|
| +
|
| + position_string += '-';
|
| + position_string += base::IntToString(position_in_parent);
|
| +
|
| + child = parent;
|
| + parent = parent->parent();
|
| + }
|
| +
|
| + // NOTE: The generated string is not guaranteed to be unique, but should
|
| + // have a better chance of being unique than the string generated by
|
| + // GenerateCandidate, because we embed extra information into the string:
|
| + // 1) we walk the full chain of ancestors, all the way to the main frame
|
| + // 2) we use frame-position-within-parent (aka |position_in_parent|)
|
| + // instead of sibling-count.
|
| + return position_string;
|
| +}
|
| +
|
| +std::string AppendUniqueSuffix(blink::WebFrame* top,
|
| + const std::string& prefix,
|
| + const std::string& likely_unique_suffix) {
|
| + // We want unique name to be stable across page reloads - this is why
|
| + // we use a deterministic |number_of_tries| rather than a random number
|
| + // (a random number would be more likely to avoid a collision, but
|
| + // would change after every page reload).
|
| + int number_of_retries = 0;
|
| +
|
| + // Keep trying |prefix| + |likely_unique_suffix| + |number_of_tries|
|
| + // concatenations until we get a truly unique name.
|
| + std::string candidate(prefix);
|
| + candidate += likely_unique_suffix;
|
| + candidate += '/';
|
| + while (true) {
|
| + size_t current_length = candidate.size();
|
| + candidate += base::IntToString(number_of_retries++);
|
| + candidate += "-->";
|
| + if (!UniqueNameExists(top, candidate))
|
| + break;
|
| + candidate.resize(current_length);
|
| + }
|
| + return candidate;
|
| +}
|
| +
|
| +std::string CalculateNewName(blink::WebFrame* parent,
|
| + blink::WebFrame* child,
|
| + const std::string& name) {
|
| + blink::WebFrame* top = parent->top();
|
| + if (!name.empty() && !UniqueNameExists(top, name) && name != "_blank")
|
| + return name;
|
| +
|
| + std::string candidate = GenerateCandidate(parent, child);
|
| + if (!UniqueNameExists(top, candidate))
|
| + return candidate;
|
| +
|
| + std::string likely_unique_suffix = GenerateFramePosition(parent, child);
|
| + return AppendUniqueSuffix(top, candidate, likely_unique_suffix);
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +UniqueNameHelper::UniqueNameHelper(RenderFrameImpl* render_frame)
|
| + : render_frame_(render_frame) {}
|
| +
|
| +UniqueNameHelper::~UniqueNameHelper() {}
|
| +
|
| +std::string UniqueNameHelper::GenerateNameForNewChildFrame(
|
| + blink::WebFrame* parent,
|
| + const std::string& name) {
|
| + return CalculateNewName(parent, nullptr, name);
|
| +}
|
| +
|
| +void UniqueNameHelper::UpdateName(const std::string& name) {
|
| + // The unique name of the main frame is always the empty string.
|
| + if (!GetWebFrame()->parent())
|
| + return;
|
| + // It's important to clear this before calculating a new name, as the
|
| + // calculation checks for collisions with existing unique names.
|
| + unique_name_.clear();
|
| + unique_name_ = CalculateNewName(GetWebFrame()->parent(), GetWebFrame(), name);
|
| +}
|
| +
|
| +blink::WebLocalFrame* UniqueNameHelper::GetWebFrame() const {
|
| + return render_frame_->GetWebFrame();
|
| +}
|
| +
|
| +} // namespace content
|
|
|