blob: dbad598d35fab42702657cdd34352120eea1a609 [file] [log] [blame]
// Copyright 2015 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 "chrome/common/media_router/media_source.h"
#include <algorithm>
#include <array>
#include <cstdio>
#include <ostream>
#include <string>
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "chrome/common/media_router/media_source.h"
#include "url/gurl.h"
namespace media_router {
namespace {
// Prefixes used to format and detect various protocols' media source URNs.
// See: https://www.ietf.org/rfc/rfc3406.txt
constexpr char kTabMediaUrnFormat[] = "urn:x-org.chromium.media:source:tab:%d";
constexpr char kDesktopMediaUrn[] = "urn:x-org.chromium.media:source:desktop";
constexpr char kTabRemotingUrnFormat[] =
"urn:x-org.chromium.media:source:tab_content_remoting:%d";
// List of non-http(s) schemes that are allowed in a Presentation URL.
constexpr std::array<const char* const, 5> kAllowedSchemes{
{kCastPresentationUrlScheme, kCastDialPresentationUrlScheme,
kDialPresentationUrlScheme, kRemotePlaybackPresentationUrlScheme, "test"}};
bool IsSchemeAllowed(const GURL& url) {
return url.SchemeIsHTTPOrHTTPS() ||
std::any_of(
kAllowedSchemes.begin(), kAllowedSchemes.end(),
[&url](const char* const scheme) { return url.SchemeIs(scheme); });
}
} // namespace
bool IsLegacyCastPresentationUrl(const GURL& url) {
return base::StartsWith(url.spec(), kLegacyCastPresentationUrlPrefix,
base::CompareCase::INSENSITIVE_ASCII);
}
bool IsValidPresentationUrl(const GURL& url) {
return url.is_valid() && IsSchemeAllowed(url);
}
bool IsAutoJoinPresentationId(const std::string& presentation_id) {
return presentation_id == kAutoJoinPresentationId;
}
MediaSource::MediaSource() = default;
MediaSource::MediaSource(const MediaSource::Id& source_id) : id_(source_id) {
GURL url(source_id);
if (IsValidPresentationUrl(url))
url_ = url;
}
MediaSource::MediaSource(const GURL& presentation_url)
: id_(presentation_url.spec()), url_(presentation_url) {}
MediaSource::~MediaSource() = default;
// static
MediaSource MediaSource::ForTab(int tab_id) {
return MediaSource(base::StringPrintf(kTabMediaUrnFormat, tab_id));
}
// static
MediaSource MediaSource::ForTabContentRemoting(int tab_id) {
return MediaSource(base::StringPrintf(kTabRemotingUrnFormat, tab_id));
}
// static
MediaSource MediaSource::ForDesktop() {
return MediaSource(std::string(kDesktopMediaUrn));
}
// static
MediaSource MediaSource::ForPresentationUrl(const GURL& presentation_url) {
return MediaSource(presentation_url);
}
bool MediaSource::IsDesktopMirroringSource() const {
return base::StartsWith(id(), kDesktopMediaUrn, base::CompareCase::SENSITIVE);
}
bool MediaSource::IsTabMirroringSource() const {
int tab_id;
return std::sscanf(id_.c_str(), kTabMediaUrnFormat, &tab_id) == 1 &&
tab_id > 0;
}
bool MediaSource::IsMirroringSource() const {
return IsDesktopMirroringSource() || IsTabMirroringSource();
}
bool MediaSource::IsCastPresentationUrl() const {
return url_.SchemeIs(kCastPresentationUrlScheme) ||
IsLegacyCastPresentationUrl(url_);
}
int MediaSource::TabId() const {
int tab_id;
if (sscanf(id_.c_str(), kTabMediaUrnFormat, &tab_id) == 1)
return tab_id;
else if (sscanf(id_.c_str(), kTabRemotingUrnFormat, &tab_id) == 1)
return tab_id;
else
return -1;
}
bool MediaSource::IsValid() const {
return TabId() > 0 || IsDesktopMirroringSource() ||
IsValidPresentationUrl(GURL(id_));
}
bool MediaSource::IsDialSource() const {
return url_.SchemeIs(kCastDialPresentationUrlScheme);
}
std::string MediaSource::AppNameFromDialSource() const {
return IsDialSource() ? url_.path() : "";
}
} // namespace media_router