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 "PageConsole.h"
31
32#include "Chrome.h"
33#include "ChromeClient.h"
34#include "ConsoleAPITypes.h"
35#include "ConsoleTypes.h"
36#include "Document.h"
37#include "Frame.h"
38#include "InspectorConsoleInstrumentation.h"
39#include "InspectorController.h"
40#include "Page.h"
41#include "ScriptArguments.h"
42#include "ScriptCallStack.h"
43#include "ScriptCallStackFactory.h"
44#include "ScriptValue.h"
45#include "ScriptableDocumentParser.h"
46#include "Settings.h"
47#include <stdio.h>
48#include <wtf/text/CString.h>
49#include <wtf/text/WTFString.h>
50
51namespace WebCore {
52
53namespace {
54    int muteCount = 0;
55}
56
57PageConsole::PageConsole(Page* page) : m_page(page) { }
58
59PageConsole::~PageConsole() { }
60
61void PageConsole::printSourceURLAndLine(const String& sourceURL, unsigned lineNumber)
62{
63    if (!sourceURL.isEmpty()) {
64        if (lineNumber > 0)
65            printf("%s:%d: ", sourceURL.utf8().data(), lineNumber);
66        else
67            printf("%s: ", sourceURL.utf8().data());
68    }
69}
70
71void PageConsole::printMessageSourceAndLevelPrefix(MessageSource source, MessageLevel level)
72{
73    const char* sourceString;
74    switch (source) {
75    case XMLMessageSource:
76        sourceString = "XML";
77        break;
78    case JSMessageSource:
79        sourceString = "JS";
80        break;
81    case NetworkMessageSource:
82        sourceString = "NETWORK";
83        break;
84    case ConsoleAPIMessageSource:
85        sourceString = "CONSOLEAPI";
86        break;
87    case StorageMessageSource:
88        sourceString = "STORAGE";
89        break;
90    case AppCacheMessageSource:
91        sourceString = "APPCACHE";
92        break;
93    case RenderingMessageSource:
94        sourceString = "RENDERING";
95        break;
96    case CSSMessageSource:
97        sourceString = "CSS";
98        break;
99    case SecurityMessageSource:
100        sourceString = "SECURITY";
101        break;
102    case OtherMessageSource:
103        sourceString = "OTHER";
104        break;
105    default:
106        ASSERT_NOT_REACHED();
107        sourceString = "UNKNOWN";
108        break;
109    }
110
111    const char* levelString;
112    switch (level) {
113    case DebugMessageLevel:
114        levelString = "DEBUG";
115        break;
116    case LogMessageLevel:
117        levelString = "LOG";
118        break;
119    case WarningMessageLevel:
120        levelString = "WARN";
121        break;
122    case ErrorMessageLevel:
123        levelString = "ERROR";
124        break;
125    default:
126        ASSERT_NOT_REACHED();
127        levelString = "UNKNOWN";
128        break;
129    }
130
131    printf("%s %s:", sourceString, levelString);
132}
133
134void PageConsole::addMessage(MessageSource source, MessageLevel level, const String& message, unsigned long requestIdentifier, Document* document)
135{
136    String url;
137    if (document)
138        url = document->url().string();
139    // FIXME: <http://webkit.org/b/114319> PageConsole::addMessage should automatically determine column number alongside line number
140    unsigned line = 0;
141    if (document && document->parsing() && !document->isInDocumentWrite() && document->scriptableDocumentParser()) {
142        ScriptableDocumentParser* parser = document->scriptableDocumentParser();
143        if (!parser->isWaitingForScripts() && !parser->isExecutingScript())
144            line = parser->lineNumber().oneBasedInt();
145    }
146    addMessage(source, level, message, url, line, 0, 0, 0, requestIdentifier);
147}
148
149void PageConsole::addMessage(MessageSource source, MessageLevel level, const String& message, PassRefPtr<ScriptCallStack> callStack)
150{
151    addMessage(source, level, message, String(), 0, 0, callStack, 0);
152}
153
154void PageConsole::addMessage(MessageSource source, MessageLevel level, const String& message, const String& url, unsigned lineNumber, unsigned columnNumber, PassRefPtr<ScriptCallStack> callStack, ScriptState* state, unsigned long requestIdentifier)
155{
156    if (muteCount && source != ConsoleAPIMessageSource)
157        return;
158
159    Page* page = this->page();
160    if (!page)
161        return;
162
163    if (callStack)
164        InspectorInstrumentation::addMessageToConsole(page, source, LogMessageType, level, message, callStack, requestIdentifier);
165    else
166        InspectorInstrumentation::addMessageToConsole(page, source, LogMessageType, level, message, url, lineNumber, columnNumber, state, requestIdentifier);
167
168    if (source == CSSMessageSource)
169        return;
170
171    if (page->settings()->privateBrowsingEnabled())
172        return;
173
174    page->chrome().client()->addMessageToConsole(source, level, message, lineNumber, columnNumber, url);
175
176    if (!page->settings()->logsPageMessagesToSystemConsoleEnabled() && !shouldPrintExceptions())
177        return;
178
179    printSourceURLAndLine(url, lineNumber);
180    printMessageSourceAndLevelPrefix(source, level);
181
182    printf(" %s\n", message.utf8().data());
183}
184
185// static
186void PageConsole::mute()
187{
188    muteCount++;
189}
190
191// static
192void PageConsole::unmute()
193{
194    ASSERT(muteCount > 0);
195    muteCount--;
196}
197
198static bool printExceptions = false;
199
200bool PageConsole::shouldPrintExceptions()
201{
202    return printExceptions;
203}
204
205void PageConsole::setShouldPrintExceptions(bool print)
206{
207    printExceptions = print;
208}
209
210} // namespace WebCore
211