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