chromium/chrome/browser/feed/rss_links_fetcher.cc

// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/feed/rss_links_fetcher.h"

#include "base/functional/callback.h"
#include "components/feed/mojom/rss_link_reader.mojom.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
#include "services/service_manager/public/cpp/interface_provider.h"

namespace feed {
namespace {

mojo::Remote<feed::mojom::RssLinkReader> GetRssLinkReaderRemote(
    content::WebContents* web_contents) {
  DCHECK(web_contents->GetPrimaryMainFrame()->IsRenderFrameLive());
  mojo::Remote<feed::mojom::RssLinkReader> result;
  // GetRemoteInterfaces() cannot be null if the render frame is created.
  web_contents->GetPrimaryMainFrame()->GetRemoteInterfaces()->GetInterface(
      result.BindNewPipeAndPassReceiver());
  return result;
}

class RssLinksFetcher {
 public:
  void Start(const GURL& page_url,
             mojo::Remote<feed::mojom::RssLinkReader> link_reader,
             base::OnceCallback<void(std::vector<GURL>)> callback) {
    page_url_ = page_url;
    callback_ = std::move(callback);
    link_reader_ = std::move(link_reader);
    if (link_reader_) {
      // Unretained is OK here. The `mojo::Remote` will not invoke callbacks
      // after it is destroyed.
      link_reader_.set_disconnect_handler(base::BindOnce(
          &RssLinksFetcher::SendResultAndDeleteSelf, base::Unretained(this)));
      link_reader_->GetRssLinks(base::BindOnce(
          &RssLinksFetcher::GetRssLinksComplete, base::Unretained(this)));
      return;
    }
    SendResultAndDeleteSelf();
  }

 private:
  void GetRssLinksComplete(feed::mojom::RssLinksPtr rss_links) {
    if (rss_links) {
      if (rss_links->page_url == page_url_) {
        for (GURL& link : rss_links->links) {
          if (link.is_valid() && link.SchemeIsHTTPOrHTTPS()) {
            result_.push_back(std::move(link));
          }
        }
      }
    }

    SendResultAndDeleteSelf();
  }
  void SendResultAndDeleteSelf() {
    std::move(callback_).Run(std::move(result_));
    delete this;
  }

  GURL page_url_;
  mojo::Remote<feed::mojom::RssLinkReader> link_reader_;
  std::vector<GURL> result_;
  base::OnceCallback<void(std::vector<GURL>)> callback_;
};

void FetchRssLinksHelper(const GURL& url,
                         mojo::Remote<feed::mojom::RssLinkReader> link_reader,
                         base::OnceCallback<void(std::vector<GURL>)> callback) {
  // RssLinksFetcher is self-deleting.
  auto* fetcher = new RssLinksFetcher();
  fetcher->Start(url, std::move(link_reader), std::move(callback));
}

}  // namespace

void FetchRssLinksForTesting(
    const GURL& url,
    mojo::Remote<feed::mojom::RssLinkReader> link_reader,
    base::OnceCallback<void(std::vector<GURL>)> callback) {
  FetchRssLinksHelper(url, std::move(link_reader), std::move(callback));
}

void FetchRssLinks(const GURL& url,
                   content::WebContents* web_contents,
                   base::OnceCallback<void(std::vector<GURL>)> callback) {
  if (!web_contents) {
    std::move(callback).Run(std::vector<GURL>());
    return;
  }
  FetchRssLinksHelper(url, GetRssLinkReaderRemote(web_contents),
                      std::move(callback));
}

}  // namespace feed