1/* 2 * Copyright (C) 2013 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of 14 * its contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29#include "config.h" 30#include "core/frame/FrameConsole.h" 31 32#include "bindings/core/v8/ScriptCallStackFactory.h" 33#include "core/frame/FrameHost.h" 34#include "core/inspector/ConsoleAPITypes.h" 35#include "core/inspector/ConsoleMessage.h" 36#include "core/inspector/ConsoleMessageStorage.h" 37#include "core/inspector/InspectorConsoleInstrumentation.h" 38#include "core/inspector/ScriptCallStack.h" 39#include "core/page/Chrome.h" 40#include "core/page/ChromeClient.h" 41#include "core/page/Page.h" 42#include "core/workers/WorkerGlobalScopeProxy.h" 43#include "platform/network/ResourceResponse.h" 44#include "wtf/text/StringBuilder.h" 45 46namespace blink { 47 48static const HashSet<int>& allClientReportingMessageTypes() 49{ 50 DEFINE_STATIC_LOCAL(HashSet<int>, types, ()); 51 if (types.isEmpty()) { 52 types.add(LogMessageType); 53 types.add(DirMessageType); 54 types.add(DirXMLMessageType); 55 types.add(TableMessageType); 56 types.add(TraceMessageType); 57 types.add(ClearMessageType); 58 types.add(AssertMessageType); 59 } 60 return types; 61} 62 63namespace { 64 65int muteCount = 0; 66 67} 68 69FrameConsole::FrameConsole(LocalFrame& frame) 70 : m_frame(&frame) 71{ 72} 73 74DEFINE_EMPTY_DESTRUCTOR_WILL_BE_REMOVED(FrameConsole); 75 76void FrameConsole::addMessage(PassRefPtrWillBeRawPtr<ConsoleMessage> prpConsoleMessage) 77{ 78 RefPtrWillBeRawPtr<ConsoleMessage> consoleMessage = prpConsoleMessage; 79 if (muteCount && consoleMessage->source() != ConsoleAPIMessageSource) 80 return; 81 82 // FIXME: This should not need to reach for the main-frame. 83 // Inspector code should just take the current frame and know how to walk itself. 84 ExecutionContext* context = frame().document(); 85 if (!context) 86 return; 87 88 String messageURL; 89 unsigned lineNumber = 0; 90 if (consoleMessage->callStack() && consoleMessage->callStack()->size()) { 91 lineNumber = consoleMessage->callStack()->at(0).lineNumber(); 92 messageURL = consoleMessage->callStack()->at(0).sourceURL(); 93 } else { 94 lineNumber = consoleMessage->lineNumber(); 95 messageURL = consoleMessage->url(); 96 } 97 98 messageStorage()->reportMessage(consoleMessage); 99 100 if (consoleMessage->source() == CSSMessageSource || consoleMessage->source() == NetworkMessageSource) 101 return; 102 103 RefPtrWillBeRawPtr<ScriptCallStack> reportedCallStack = nullptr; 104 if (consoleMessage->source() != ConsoleAPIMessageSource) { 105 if (consoleMessage->callStack() && frame().chromeClient().shouldReportDetailedMessageForSource(messageURL)) 106 reportedCallStack = consoleMessage->callStack(); 107 } else { 108 if (!frame().host() || (consoleMessage->scriptArguments() && !consoleMessage->scriptArguments()->argumentCount())) 109 return; 110 111 if (!allClientReportingMessageTypes().contains(consoleMessage->type())) 112 return; 113 114 if (frame().chromeClient().shouldReportDetailedMessageForSource(messageURL)) 115 reportedCallStack = createScriptCallStack(ScriptCallStack::maxCallStackSizeToCapture); 116 } 117 118 String stackTrace; 119 if (reportedCallStack) 120 stackTrace = FrameConsole::formatStackTraceString(consoleMessage->message(), reportedCallStack); 121 frame().chromeClient().addMessageToConsole(m_frame, consoleMessage->source(), consoleMessage->level(), consoleMessage->message(), lineNumber, messageURL, stackTrace); 122} 123 124void FrameConsole::reportResourceResponseReceived(DocumentLoader* loader, unsigned long requestIdentifier, const ResourceResponse& response) 125{ 126 if (!loader) 127 return; 128 if (response.httpStatusCode() < 400) 129 return; 130 String message = "Failed to load resource: the server responded with a status of " + String::number(response.httpStatusCode()) + " (" + response.httpStatusText() + ')'; 131 RefPtrWillBeRawPtr<ConsoleMessage> consoleMessage = ConsoleMessage::create(NetworkMessageSource, ErrorMessageLevel, message, response.url().string()); 132 consoleMessage->setRequestIdentifier(requestIdentifier); 133 addMessage(consoleMessage.release()); 134} 135 136String FrameConsole::formatStackTraceString(const String& originalMessage, PassRefPtrWillBeRawPtr<ScriptCallStack> callStack) 137{ 138 StringBuilder stackTrace; 139 for (size_t i = 0; i < callStack->size(); ++i) { 140 const ScriptCallFrame& frame = callStack->at(i); 141 stackTrace.append("\n at " + (frame.functionName().length() ? frame.functionName() : "(anonymous function)")); 142 stackTrace.appendLiteral(" ("); 143 stackTrace.append(frame.sourceURL()); 144 stackTrace.append(':'); 145 stackTrace.appendNumber(frame.lineNumber()); 146 stackTrace.append(':'); 147 stackTrace.appendNumber(frame.columnNumber()); 148 stackTrace.append(')'); 149 } 150 151 return stackTrace.toString(); 152} 153 154void FrameConsole::mute() 155{ 156 muteCount++; 157} 158 159void FrameConsole::unmute() 160{ 161 ASSERT(muteCount > 0); 162 muteCount--; 163} 164 165ConsoleMessageStorage* FrameConsole::messageStorage() 166{ 167 LocalFrame* curFrame = m_frame; 168 Frame* topFrame = curFrame->tree().top(); 169 ASSERT(topFrame->isLocalFrame()); 170 LocalFrame* localTopFrame = toLocalFrame(topFrame); 171 if (localTopFrame != curFrame) 172 return localTopFrame->console().messageStorage(); 173 if (!m_consoleMessageStorage) 174 m_consoleMessageStorage = ConsoleMessageStorage::createForFrame(m_frame); 175 return m_consoleMessageStorage.get(); 176} 177 178void FrameConsole::clearMessages() 179{ 180 messageStorage()->clear(); 181} 182 183void FrameConsole::adoptWorkerMessagesAfterTermination(WorkerGlobalScopeProxy* proxy) 184{ 185 messageStorage()->adoptWorkerMessagesAfterTermination(proxy); 186} 187 188void FrameConsole::trace(Visitor* visitor) 189{ 190 visitor->trace(m_frame); 191 visitor->trace(m_consoleMessageStorage); 192} 193 194} // namespace blink 195