1// Copyright 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 "extensions/browser/extension_error.h" 6 7#include "base/json/json_reader.h" 8#include "base/strings/string_number_conversions.h" 9#include "base/strings/utf_string_conversions.h" 10#include "base/values.h" 11#include "extensions/common/constants.h" 12#include "url/gurl.h" 13 14using base::string16; 15 16namespace extensions { 17 18namespace { 19 20const char kLineNumberKey[] = "lineNumber"; 21const char kColumnNumberKey[] = "columnNumber"; 22const char kURLKey[] = "url"; 23const char kFunctionNameKey[] = "functionName"; 24const char kExecutionContextURLKey[] = "executionContextURL"; 25const char kStackTraceKey[] = "stackTrace"; 26 27// Try to retrieve an extension ID from a |url|. On success, returns true and 28// populates |extension_id| with the ID. On failure, returns false and leaves 29// extension_id untouched. 30bool GetExtensionIDFromGURL(const GURL& url, std::string* extension_id) { 31 if (url.SchemeIs(kExtensionScheme)) { 32 *extension_id = url.host(); 33 return true; 34 } 35 return false; 36} 37 38} // namespace 39 40ExtensionError::ExtensionError(Type type, 41 const std::string& extension_id, 42 bool from_incognito, 43 const string16& source, 44 const string16& message) 45 : type_(type), 46 extension_id_(extension_id), 47 from_incognito_(from_incognito), 48 source_(source), 49 message_(message) { 50} 51 52ExtensionError::~ExtensionError() { 53} 54 55std::string ExtensionError::PrintForTest() const { 56 return std::string("Extension Error:") + 57 "\n OTR: " + std::string(from_incognito_ ? "true" : "false") + 58 "\n Source: " + base::UTF16ToUTF8(source_) + 59 "\n Message: " + base::UTF16ToUTF8(message_) + 60 "\n ID: " + extension_id_; 61} 62 63ManifestParsingError::ManifestParsingError(const std::string& extension_id, 64 const string16& message) 65 : ExtensionError(ExtensionError::MANIFEST_PARSING_ERROR, 66 extension_id, 67 false, // extensions can't be installed while incognito. 68 base::FilePath(kManifestFilename).AsUTF16Unsafe(), 69 message) { 70} 71 72ManifestParsingError::~ManifestParsingError() { 73} 74 75std::string ManifestParsingError::PrintForTest() const { 76 return ExtensionError::PrintForTest() + 77 "\n Type: ManifestParsingError"; 78} 79 80JavascriptRuntimeError::StackFrame::StackFrame() : line_number(-1), 81 column_number(-1) { 82} 83 84JavascriptRuntimeError::StackFrame::StackFrame(size_t frame_line, 85 size_t frame_column, 86 const string16& frame_url, 87 const string16& frame_function) 88 : line_number(frame_line), 89 column_number(frame_column), 90 url(frame_url), 91 function(frame_function) { 92} 93 94JavascriptRuntimeError::StackFrame::~StackFrame() { 95} 96 97JavascriptRuntimeError::JavascriptRuntimeError(bool from_incognito, 98 const string16& source, 99 const string16& message, 100 logging::LogSeverity level, 101 const string16& details) 102 : ExtensionError(ExtensionError::JAVASCRIPT_RUNTIME_ERROR, 103 std::string(), // We don't know the id yet. 104 from_incognito, 105 source, 106 message), 107 level_(level) { 108 ParseDetails(details); 109 DetermineExtensionID(); 110} 111 112JavascriptRuntimeError::~JavascriptRuntimeError() { 113} 114 115std::string JavascriptRuntimeError::PrintForTest() const { 116 std::string result = ExtensionError::PrintForTest() + 117 "\n Type: JavascriptRuntimeError" 118 "\n Context: " + base::UTF16ToUTF8(execution_context_url_) + 119 "\n Stack Trace: "; 120 for (StackTrace::const_iterator iter = stack_trace_.begin(); 121 iter != stack_trace_.end(); ++iter) { 122 result += "\n {" 123 "\n Line: " + base::IntToString(iter->line_number) + 124 "\n Column: " + base::IntToString(iter->column_number) + 125 "\n URL: " + base::UTF16ToUTF8(iter->url) + 126 "\n Function: " + base::UTF16ToUTF8(iter->function) + 127 "\n }"; 128 } 129 return result; 130} 131 132void JavascriptRuntimeError::ParseDetails(const string16& details) { 133 scoped_ptr<base::Value> value( 134 base::JSONReader::Read(base::UTF16ToUTF8(details))); 135 const base::DictionaryValue* details_value; 136 const base::ListValue* trace_value = NULL; 137 138 // The |details| value should contain an execution context url and a stack 139 // trace. 140 if (!value.get() || 141 !value->GetAsDictionary(&details_value) || 142 !details_value->GetString(kExecutionContextURLKey, 143 &execution_context_url_) || 144 !details_value->GetList(kStackTraceKey, &trace_value)) { 145 NOTREACHED(); 146 return; 147 } 148 149 int line = 0; 150 int column = 0; 151 string16 url; 152 153 for (size_t i = 0; i < trace_value->GetSize(); ++i) { 154 const base::DictionaryValue* frame_value = NULL; 155 CHECK(trace_value->GetDictionary(i, &frame_value)); 156 157 frame_value->GetInteger(kLineNumberKey, &line); 158 frame_value->GetInteger(kColumnNumberKey, &column); 159 frame_value->GetString(kURLKey, &url); 160 161 string16 function; 162 frame_value->GetString(kFunctionNameKey, &function); // This can be empty. 163 stack_trace_.push_back(StackFrame(line, column, url, function)); 164 } 165} 166 167void JavascriptRuntimeError::DetermineExtensionID() { 168 if (!GetExtensionIDFromGURL(GURL(source_), &extension_id_)) 169 GetExtensionIDFromGURL(GURL(execution_context_url_), &extension_id_); 170} 171 172} // namespace extensions 173