blob: 1f7dd3f4d2c82eea04646e44c29ae9ee3416ce97 [file] [log] [blame]
kmarshalld2f3bea2015-03-11 23:42:221// Copyright 2015 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
takumifa34e51932017-04-19 20:38:005#include "chrome/common/media_router/media_source.h"
kmarshalld2f3bea2015-03-11 23:42:226
John Williamsd48d028c2019-05-23 23:59:127#include <algorithm>
8#include <array>
9#include <cstdio>
John Williamse955a24812019-01-19 01:35:0010#include <ostream>
kmarshalld2f3bea2015-03-11 23:42:2211#include <string>
12
John Williamsd48d028c2019-05-23 23:59:1213#include "base/strings/string_util.h"
14#include "base/strings/stringprintf.h"
15#include "chrome/common/media_router/media_source.h"
16#include "url/gurl.h"
zhaobine1ed84732016-12-20 23:16:3417
kmarshalld2f3bea2015-03-11 23:42:2218namespace media_router {
19
John Williamsd48d028c2019-05-23 23:59:1220namespace {
21
22// Prefixes used to format and detect various protocols' media source URNs.
23// See: https://www.ietf.org/rfc/rfc3406.txt
Jordan Bayles89346462020-05-26 21:36:1224constexpr char kAnyTabMediaUrn[] = "urn:x-org.chromium.media:source:tab:*";
John Williamsd48d028c2019-05-23 23:59:1225constexpr char kTabMediaUrnFormat[] = "urn:x-org.chromium.media:source:tab:%d";
John Williams4c353442019-11-13 23:37:0026constexpr base::StringPiece kDesktopMediaUrnPrefix =
27 "urn:x-org.chromium.media:source:desktop:";
28constexpr base::StringPiece kUnknownDesktopMediaUrn =
29 "urn:x-org.chromium.media:source:desktop";
John Williamsd48d028c2019-05-23 23:59:1230
31// List of non-http(s) schemes that are allowed in a Presentation URL.
32constexpr std::array<const char* const, 5> kAllowedSchemes{
33 {kCastPresentationUrlScheme, kCastDialPresentationUrlScheme,
34 kDialPresentationUrlScheme, kRemotePlaybackPresentationUrlScheme, "test"}};
35
36bool IsSchemeAllowed(const GURL& url) {
37 return url.SchemeIsHTTPOrHTTPS() ||
38 std::any_of(
39 kAllowedSchemes.begin(), kAllowedSchemes.end(),
40 [&url](const char* const scheme) { return url.SchemeIs(scheme); });
41}
42
43} // namespace
44
45bool IsLegacyCastPresentationUrl(const GURL& url) {
46 return base::StartsWith(url.spec(), kLegacyCastPresentationUrlPrefix,
47 base::CompareCase::INSENSITIVE_ASCII);
48}
49
50bool IsValidPresentationUrl(const GURL& url) {
51 return url.is_valid() && IsSchemeAllowed(url);
52}
53
54bool IsAutoJoinPresentationId(const std::string& presentation_id) {
55 return presentation_id == kAutoJoinPresentationId;
56}
57
58MediaSource::MediaSource() = default;
59
kmarshall5fa0263d2015-06-03 16:07:0860MediaSource::MediaSource(const MediaSource::Id& source_id) : id_(source_id) {
zhaobine1ed84732016-12-20 23:16:3461 GURL url(source_id);
62 if (IsValidPresentationUrl(url))
63 url_ = url;
imcheng2ae6fd32015-04-10 17:59:1864}
65
mfoltz7a2c823b2016-10-08 01:35:2466MediaSource::MediaSource(const GURL& presentation_url)
zhaobin81cb26bf2016-12-07 19:42:5567 : id_(presentation_url.spec()), url_(presentation_url) {}
mfoltz7a2c823b2016-10-08 01:35:2468
John Williamsd48d028c2019-05-23 23:59:1269MediaSource::~MediaSource() = default;
kmarshalld2f3bea2015-03-11 23:42:2270
John Williamsd48d028c2019-05-23 23:59:1271// static
John Williams479d9902020-06-04 17:09:3472MediaSource MediaSource::ForLocalFile() {
73 // TODO(crbug.com/1090878): Use something more sane here. Fixing this
74 // requires tracking down other places where tab ID 0 is used to indicate
75 // local file casting.
76 //
77 // This probably isn't a source of bugs in practice, because tab IDs are
78 // generated by SessionIdGenerator, which appears to only produce positive
79 // values, but that fact isn't clearly documentated, and other parts of
80 // Chromium don't seem to rely on it, using -1 as the canonical invalid tab
81 // ID.
82 return MediaSource(base::StringPrintf(kTabMediaUrnFormat, 0));
83}
84
85// static
Jordan Bayles89346462020-05-26 21:36:1286MediaSource MediaSource::ForAnyTab() {
87 return MediaSource(std::string(kAnyTabMediaUrn));
88}
89
90// static
John Williamsd48d028c2019-05-23 23:59:1291MediaSource MediaSource::ForTab(int tab_id) {
John Williams479d9902020-06-04 17:09:3492 // Ideally we shouldn't allow -1 as a tab ID, but in unit tests, a tab ID of
93 // -1 can show up when this function is called from
94 // CastHandler::StartObservingForSinks() because SessionTabHelper::IdForTab
95 // can return -1.
96 DCHECK_GE(tab_id, -1);
John Williamsd48d028c2019-05-23 23:59:1297 return MediaSource(base::StringPrintf(kTabMediaUrnFormat, tab_id));
kmarshalld2f3bea2015-03-11 23:42:2298}
99
John Williamsd48d028c2019-05-23 23:59:12100// static
John Williams4c353442019-11-13 23:37:00101MediaSource MediaSource::ForDesktop(const std::string& desktop_media_id) {
John Williams479d9902020-06-04 17:09:34102 DCHECK(!desktop_media_id.empty());
John Williams4c353442019-11-13 23:37:00103 return MediaSource(kDesktopMediaUrnPrefix.as_string() + desktop_media_id);
104}
105
106// static
John Williamsd48d028c2019-05-23 23:59:12107MediaSource MediaSource::ForDesktop() {
John Williams4c353442019-11-13 23:37:00108 return MediaSource(kUnknownDesktopMediaUrn.as_string());
imcheng2ae6fd32015-04-10 17:59:18109}
110
John Williamsd48d028c2019-05-23 23:59:12111// static
112MediaSource MediaSource::ForPresentationUrl(const GURL& presentation_url) {
113 return MediaSource(presentation_url);
Bin Zhao3e0c55d2018-03-16 23:40:51114}
115
Jordan Bayles89346462020-05-26 21:36:12116bool MediaSource::IsTabMirroringSource() const {
John Williams479d9902020-06-04 17:09:34117 return id() == kAnyTabMediaUrn || TabId() > 0;
Jordan Bayles89346462020-05-26 21:36:12118}
119
John Williamsd48d028c2019-05-23 23:59:12120bool MediaSource::IsDesktopMirroringSource() const {
John Williams4c353442019-11-13 23:37:00121 return id() == kUnknownDesktopMediaUrn ||
122 base::StartsWith(id(), kDesktopMediaUrnPrefix,
123 base::CompareCase::SENSITIVE);
John Williamsd48d028c2019-05-23 23:59:12124}
125
John Williams479d9902020-06-04 17:09:34126bool MediaSource::IsLocalFileSource() const {
127 // TODO(crbug.com/1090878): Keep this method is sync with ForLocalFile().
128 return TabId() == 0;
John Williamsd48d028c2019-05-23 23:59:12129}
130
131bool MediaSource::IsCastPresentationUrl() const {
132 return url_.SchemeIs(kCastPresentationUrlScheme) ||
133 IsLegacyCastPresentationUrl(url_);
134}
135
136int MediaSource::TabId() const {
John Williams479d9902020-06-04 17:09:34137 int tab_id = -1;
138 sscanf(id_.c_str(), kTabMediaUrnFormat, &tab_id);
139 return tab_id;
John Williamsd48d028c2019-05-23 23:59:12140}
141
John Williams4c353442019-11-13 23:37:00142base::Optional<std::string> MediaSource::DesktopStreamId() const {
143 if (base::StartsWith(id_, kDesktopMediaUrnPrefix,
144 base::CompareCase::SENSITIVE)) {
145 return std::string(id_.begin() + kDesktopMediaUrnPrefix.size(), id_.end());
146 }
147 return base::nullopt;
148}
149
John Williamsd48d028c2019-05-23 23:59:12150bool MediaSource::IsDialSource() const {
151 return url_.SchemeIs(kCastDialPresentationUrlScheme);
152}
153
154std::string MediaSource::AppNameFromDialSource() const {
155 return IsDialSource() ? url_.path() : "";
156}
imchengab1bf6352017-02-16 03:30:07157
Takumi Fujimoto979451572020-06-08 23:04:58158std::string MediaSource::TruncateForLogging(size_t max_length) const {
159 const std::string origin = url_.GetOrigin().spec();
160 if (!origin.empty())
161 return origin.substr(0, max_length);
162 // TODO(takumif): Keep the query string by redacting PII. The query string may
163 // contain info useful for debugging such as the required capabilities.
164 const size_t query_start_index = id_.find("?");
165 const size_t length =
166 query_start_index == std::string::npos ? max_length : query_start_index;
167 return id_.substr(0, length);
168}
169
kmarshalld2f3bea2015-03-11 23:42:22170} // namespace media_router