1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139

content / public / browser / web_contents_media_capture_id.cc [blame]

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

#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/342213636): Remove this and spanify to fix the errors.
#pragma allow_unsafe_buffers
#endif

#include "content/public/browser/web_contents_media_capture_id.h"

#include <string_view>
#include <tuple>

#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"

namespace {
constexpr char kDisableLocalEchoFlag[] = "local_echo=false";
constexpr char kOptionStart = '?';
constexpr char kOptionSeparator = '&';

bool ExtractTabCaptureTarget(const std::string& device_id_param,
                             int* render_process_id,
                             int* main_render_frame_id) {
  const std::string device_scheme = content::kWebContentsCaptureScheme;
  if (!base::StartsWith(device_id_param, device_scheme,
                        base::CompareCase::SENSITIVE))
    return false;

  const std::string device_id = device_id_param.substr(device_scheme.size());

  const size_t sep_pos = device_id.find(':');
  if (sep_pos == std::string::npos)
    return false;

  const std::string_view component1(device_id.data(), sep_pos);
  size_t end_pos = device_id.find('?');
  if (end_pos == std::string::npos)
    end_pos = device_id.length();
  const std::string_view component2(device_id.data() + sep_pos + 1,
                                    end_pos - sep_pos - 1);

  return (base::StringToInt(component1, render_process_id) &&
          base::StringToInt(component2, main_render_frame_id));
}

bool ExtractOptions(const std::string& device_id,
                    bool* disable_local_echo) {
  DCHECK(disable_local_echo);
  *disable_local_echo = false;

  // Find the option part of the string and just do a naive string compare since
  // there are no other options in the |device_id| to account for (at the time
  // of this writing).
  size_t option_pos = device_id.find(kOptionStart);
  if (option_pos == std::string::npos)
    return true;

  size_t option_pos_end;
  while (option_pos < device_id.length()) {
    option_pos_end = device_id.find(kOptionSeparator, option_pos + 1);
    if (option_pos_end == std::string::npos)
      option_pos_end = device_id.length();
    const std::string_view component(device_id.data() + option_pos + 1,
                                     option_pos_end - option_pos - 1);

    if (component.compare(kDisableLocalEchoFlag) == 0)
      *disable_local_echo = true;
    else  // Some unknown parameter is specified, and thus this ID is invalid.
      return false;

    option_pos = option_pos_end;
  }
  return true;
}

}  // namespace

namespace content {

const char kWebContentsCaptureScheme[] = "web-contents-media-stream://";

bool WebContentsMediaCaptureId::operator<(
    const WebContentsMediaCaptureId& other) const {
  return std::tie(render_process_id, main_render_frame_id, disable_local_echo) <
         std::tie(other.render_process_id, other.main_render_frame_id,
                  other.disable_local_echo);
}

bool WebContentsMediaCaptureId::operator==(
    const WebContentsMediaCaptureId& other) const {
  return std::tie(render_process_id, main_render_frame_id,
                  disable_local_echo) == std::tie(other.render_process_id,
                                                  other.main_render_frame_id,
                                                  other.disable_local_echo);
}

bool WebContentsMediaCaptureId::is_null() const {
  return (render_process_id < 0) || (main_render_frame_id < 0);
}

std::string WebContentsMediaCaptureId::ToString() const {
  std::string s = kWebContentsCaptureScheme;
  s.append(base::NumberToString(render_process_id));
  s.append(":");
  s.append(base::NumberToString(main_render_frame_id));

  if (disable_local_echo) {
    s += kOptionStart;
    s.append(kDisableLocalEchoFlag);
  }

  return s;
}

// static
bool WebContentsMediaCaptureId::Parse(const std::string& str,
                                      WebContentsMediaCaptureId* output_id) {
  int render_process_id;
  int main_render_frame_id;
  if (!ExtractTabCaptureTarget(str, &render_process_id, &main_render_frame_id))
    return false;

  bool disable_local_echo;
  if (!ExtractOptions(str, &disable_local_echo))
    return false;

  if (output_id) {
    output_id->render_process_id = render_process_id;
    output_id->main_render_frame_id = main_render_frame_id;
    output_id->disable_local_echo = disable_local_echo;
  }

  return true;
}


}  // namespace content