Home | History | Annotate | Download | only in renderer
      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