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 46 namespace blink { 47 48 static 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 63 namespace { 64 65 int muteCount = 0; 66 67 } 68 69 FrameConsole::FrameConsole(LocalFrame& frame) 70 : m_frame(&frame) 71 { 72 } 73 74 DEFINE_EMPTY_DESTRUCTOR_WILL_BE_REMOVED(FrameConsole); 75 76 void 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 124 void 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 136 String 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 154 void FrameConsole::mute() 155 { 156 muteCount++; 157 } 158 159 void FrameConsole::unmute() 160 { 161 ASSERT(muteCount > 0); 162 muteCount--; 163 } 164 165 ConsoleMessageStorage* 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 178 void FrameConsole::clearMessages() 179 { 180 messageStorage()->clear(); 181 } 182 183 void FrameConsole::adoptWorkerMessagesAfterTermination(WorkerGlobalScopeProxy* proxy) 184 { 185 messageStorage()->adoptWorkerMessagesAfterTermination(proxy); 186 } 187 188 void FrameConsole::trace(Visitor* visitor) 189 { 190 visitor->trace(m_frame); 191 visitor->trace(m_consoleMessageStorage); 192 } 193 194 } // namespace blink 195