1 // Copyright 2014 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/renderer/extensions_render_frame_observer.h" 6 7 #include "base/strings/string_split.h" 8 #include "base/strings/utf_string_conversions.h" 9 #include "content/public/renderer/render_frame.h" 10 #include "extensions/common/extension_messages.h" 11 #include "extensions/common/stack_frame.h" 12 #include "third_party/WebKit/public/web/WebLocalFrame.h" 13 14 namespace extensions { 15 16 namespace { 17 18 // The delimiter for a stack trace provided by WebKit. 19 const char kStackFrameDelimiter[] = "\n at "; 20 21 // Get a stack trace from a WebKit console message. 22 // There are three possible scenarios: 23 // 1. WebKit gives us a stack trace in |stack_trace|. 24 // 2. The stack trace is embedded in the error |message| by an internal 25 // script. This will be more useful than |stack_trace|, since |stack_trace| 26 // will include the internal bindings trace, instead of a developer's code. 27 // 3. No stack trace is included. In this case, we should mock one up from 28 // the given line number and source. 29 // |message| will be populated with the error message only (i.e., will not 30 // include any stack trace). 31 StackTrace GetStackTraceFromMessage( 32 base::string16* message, 33 const base::string16& source, 34 const base::string16& stack_trace, 35 int32 line_number) { 36 StackTrace result; 37 std::vector<base::string16> pieces; 38 size_t index = 0; 39 40 if (message->find(base::UTF8ToUTF16(kStackFrameDelimiter)) != 41 base::string16::npos) { 42 base::SplitStringUsingSubstr(*message, 43 base::UTF8ToUTF16(kStackFrameDelimiter), 44 &pieces); 45 *message = pieces[0]; 46 index = 1; 47 } else if (!stack_trace.empty()) { 48 base::SplitStringUsingSubstr(stack_trace, 49 base::UTF8ToUTF16(kStackFrameDelimiter), 50 &pieces); 51 } 52 53 // If we got a stack trace, parse each frame from the text. 54 if (index < pieces.size()) { 55 for (; index < pieces.size(); ++index) { 56 scoped_ptr<StackFrame> frame = StackFrame::CreateFromText(pieces[index]); 57 if (frame.get()) 58 result.push_back(*frame); 59 } 60 } 61 62 if (result.empty()) { // If we don't have a stack trace, mock one up. 63 result.push_back( 64 StackFrame(line_number, 65 1u, // column number 66 source, 67 base::string16() /* no function name */ )); 68 } 69 70 return result; 71 } 72 73 } // namespace 74 75 ExtensionsRenderFrameObserver::ExtensionsRenderFrameObserver( 76 content::RenderFrame* render_frame) 77 : content::RenderFrameObserver(render_frame) { 78 } 79 80 ExtensionsRenderFrameObserver::~ExtensionsRenderFrameObserver() { 81 } 82 83 void ExtensionsRenderFrameObserver::DetailedConsoleMessageAdded( 84 const base::string16& message, 85 const base::string16& source, 86 const base::string16& stack_trace_string, 87 int32 line_number, 88 int32 severity_level) { 89 base::string16 trimmed_message = message; 90 StackTrace stack_trace = GetStackTraceFromMessage( 91 &trimmed_message, 92 source, 93 stack_trace_string, 94 line_number); 95 Send(new ExtensionHostMsg_DetailedConsoleMessageAdded( 96 routing_id(), trimmed_message, source, stack_trace, severity_level)); 97 } 98 99 void ExtensionsRenderFrameObserver::DidChangeName( 100 const base::string16& name) { 101 Send(new ExtensionHostMsg_FrameNameChanged( 102 routing_id(), 103 !render_frame()->GetWebFrame()->parent(), 104 base::UTF16ToUTF8(name))); 105 } 106 107 } // namespace extensions 108