1ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch// Copyright (c) 2013 The Chromium Authors. All rights reserved.
2ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch// Use of this source code is governed by a BSD-style license that can be
3ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch// found in the LICENSE file.
4ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch
5ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch#include "chrome/test/chromedriver/chrome/browser_info.h"
6ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch
7ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch#include "base/json/json_reader.h"
8ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch#include "base/memory/scoped_ptr.h"
9ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch#include "base/strings/string_number_conversions.h"
10ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch#include "base/strings/string_split.h"
11ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch#include "base/strings/string_util.h"
12ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch#include "base/values.h"
13ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch
14ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben MurdochBrowserInfo::BrowserInfo()
15ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch    : browser_name(std::string()),
16ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch      browser_version(std::string()),
17ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch      build_no(kToTBuildNo),
18ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch      blink_revision(kToTBlinkRevision) {
19ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch}
20ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch
21ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben MurdochBrowserInfo::BrowserInfo(std::string browser_name,
22ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch                         std::string browser_version,
23ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch                         int build_no,
24ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch                         int blink_revision)
25ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch    : browser_name(browser_name),
26ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch      browser_version(browser_version),
27ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch      build_no(build_no),
28ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch      blink_revision(blink_revision) {
29ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch}
30ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch
31ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben MurdochStatus ParseBrowserInfo(const std::string& data, BrowserInfo* browser_info) {
32ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch  scoped_ptr<base::Value> value(base::JSONReader::Read(data));
33ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch  if (!value.get())
34ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch    return Status(kUnknownError, "version info not in JSON");
35ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch
36ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch  base::DictionaryValue* dict;
37ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch  if (!value->GetAsDictionary(&dict))
38ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch    return Status(kUnknownError, "version info not a dictionary");
39ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch
40ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch  std::string browser;
41ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch  if (!dict->GetString("Browser", &browser)) {
42ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch    return Status(kUnknownError,
43ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch                  "version info doesn't include string 'Browser'");
44ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch  }
45ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch
46ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch  std::string blink_version;
47ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch  if (!dict->GetString("WebKit-Version", &blink_version)) {
48ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch    return Status(kUnknownError,
49ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch                  "version info doesn't include string 'WebKit-Version'");
50ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch  }
51ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch
52ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch  Status status = ParseBrowserString(browser, &browser_info->browser_name,
53ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch      &browser_info->browser_version, &browser_info->build_no);
54ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch
55ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch  if (status.IsError())
56ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch    return status;
57ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch
58ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch  return ParseBlinkVersionString(blink_version, &browser_info->blink_revision);
59ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch}
60ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch
61ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben MurdochStatus ParseBrowserString(const std::string& browser_string,
62ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch                          std::string* browser_name,
63ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch                          std::string* browser_version,
64ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch                          int* build_no) {
65ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch  if (browser_string.empty()) {
66ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch    *browser_name = "content shell";
67ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch    return Status(kOk);
68ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch  }
69ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch
70ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch  if (browser_string.find("Version/") == 0u) {
71ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch    *browser_name = "webview";
72ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch    return Status(kOk);
73ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch  }
74ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch
75ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch  std::string prefix = "Chrome/";
76ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch  if (browser_string.find(prefix) == 0u) {
77ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch    *browser_name = "chrome";
78ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch    *browser_version = browser_string.substr(prefix.length());
79ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch
80ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch    std::vector<std::string> version_parts;
81ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch    base::SplitString(*browser_version, '.', &version_parts);
82ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch    if (version_parts.size() != 4 ||
83ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch        !base::StringToInt(version_parts[2], build_no)) {
84ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch      return Status(kUnknownError,
85ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch                    "unrecognized Chrome version: " + *browser_version);
86ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch    }
87ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch
88ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch    return Status(kOk);
89ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch  }
90ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch
91ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch  return Status(kUnknownError,
92ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch                "unrecognized Chrome version: " + browser_string);
93ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch}
94ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch
95ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben MurdochStatus ParseBlinkVersionString(const std::string& blink_version,
96ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch                               int* blink_revision) {
97ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch  size_t before = blink_version.find('@');
98ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch  size_t after = blink_version.find(')');
99ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch  if (before == std::string::npos || after == std::string::npos) {
100ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch    return Status(kUnknownError,
101ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch                  "unrecognized Blink version string: " + blink_version);
102ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch  }
103ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch
1045b892326406927b709cdaf6c384d4ababf456332Ben Murdoch  // Chrome OS reports its Blink revision as a git hash. In this case, ignore it
1055b892326406927b709cdaf6c384d4ababf456332Ben Murdoch  // and don't set |blink_revision|. For Chrome (and for Chrome OS) we use the
1065b892326406927b709cdaf6c384d4ababf456332Ben Murdoch  // build number instead of the blink revision for decisions about backwards
1075b892326406927b709cdaf6c384d4ababf456332Ben Murdoch  // compatibility.
108ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch  std::string revision = blink_version.substr(before + 1, after - before - 1);
109ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch  if (!IsGitHash(revision) && !base::StringToInt(revision, blink_revision)) {
110ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch    return Status(kUnknownError, "unrecognized Blink revision: " + revision);
111ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch  }
112ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch
113ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch  return Status(kOk);
114ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch}
115ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch
116ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdochbool IsGitHash(const std::string& revision) {
1175b892326406927b709cdaf6c384d4ababf456332Ben Murdoch  const int kShortGitHashLength = 7;
1185b892326406927b709cdaf6c384d4ababf456332Ben Murdoch  const int kFullGitHashLength = 40;
1195b892326406927b709cdaf6c384d4ababf456332Ben Murdoch  return kShortGitHashLength <= revision.size()
1205b892326406927b709cdaf6c384d4ababf456332Ben Murdoch      && revision.size() <= kFullGitHashLength
121ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch      && base::ContainsOnlyChars(revision, "0123456789abcdefABCDEF");
122ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch}
123