1 /* 2 * Copyright (C) 2008, 2009 Google 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 are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include "config.h" 32 #include "V8Utilities.h" 33 34 #include <v8.h> 35 36 #include "Document.h" 37 #include "Frame.h" 38 #include "ScriptExecutionContext.h" 39 #include "ScriptState.h" 40 #include "V8Binding.h" 41 #include "V8Proxy.h" 42 #include "WorkerContext.h" 43 #include "WorkerContextExecutionProxy.h" 44 45 #include <wtf/Assertions.h> 46 #include "Frame.h" 47 48 namespace WebCore { 49 50 // Use an array to hold dependents. It works like a ref-counted scheme. 51 // A value can be added more than once to the DOM object. 52 void createHiddenDependency(v8::Handle<v8::Object> object, v8::Local<v8::Value> value, int cacheIndex) 53 { 54 v8::Local<v8::Value> cache = object->GetInternalField(cacheIndex); 55 if (cache->IsNull() || cache->IsUndefined()) { 56 cache = v8::Array::New(); 57 object->SetInternalField(cacheIndex, cache); 58 } 59 60 v8::Local<v8::Array> cacheArray = v8::Local<v8::Array>::Cast(cache); 61 cacheArray->Set(v8::Integer::New(cacheArray->Length()), value); 62 } 63 64 void removeHiddenDependency(v8::Handle<v8::Object> object, v8::Local<v8::Value> value, int cacheIndex) 65 { 66 v8::Local<v8::Value> cache = object->GetInternalField(cacheIndex); 67 if (!cache->IsArray()) 68 return; 69 v8::Local<v8::Array> cacheArray = v8::Local<v8::Array>::Cast(cache); 70 for (int i = cacheArray->Length() - 1; i >= 0; --i) { 71 v8::Local<v8::Value> cached = cacheArray->Get(v8::Integer::New(i)); 72 if (cached->StrictEquals(value)) { 73 cacheArray->Delete(i); 74 return; 75 } 76 } 77 } 78 79 void transferHiddenDependency(v8::Handle<v8::Object> object, 80 EventListener* oldValue, 81 v8::Local<v8::Value> newValue, 82 int cacheIndex) 83 { 84 if (oldValue) { 85 V8AbstractEventListener* oldListener = V8AbstractEventListener::cast(oldValue); 86 if (oldListener) { 87 v8::Local<v8::Object> oldListenerObject = oldListener->getExistingListenerObject(); 88 if (!oldListenerObject.IsEmpty()) 89 removeHiddenDependency(object, oldListenerObject, cacheIndex); 90 } 91 } 92 if (!newValue->IsNull() && !newValue->IsUndefined()) 93 createHiddenDependency(object, newValue, cacheIndex); 94 } 95 96 97 bool processingUserGesture() 98 { 99 Frame* frame = V8Proxy::retrieveFrameForEnteredContext(); 100 return frame && frame->script()->processingUserGesture(); 101 } 102 103 bool shouldAllowNavigation(Frame* frame) 104 { 105 Frame* callingFrame = V8Proxy::retrieveFrameForCallingContext(); 106 return callingFrame && callingFrame->loader()->shouldAllowNavigation(frame); 107 } 108 109 KURL completeURL(const String& relativeURL) 110 { 111 // For histoical reasons, we need to complete the URL using the dynamic frame. 112 Frame* frame = V8Proxy::retrieveFrameForEnteredContext(); 113 if (!frame) 114 return KURL(); 115 return frame->loader()->completeURL(relativeURL); 116 } 117 118 void navigateIfAllowed(Frame* frame, const KURL& url, bool lockHistory, bool lockBackForwardList) 119 { 120 Frame* callingFrame = V8Proxy::retrieveFrameForCallingContext(); 121 if (!callingFrame) 122 return; 123 124 if (!protocolIsJavaScript(url) || ScriptController::isSafeScript(frame)) 125 frame->redirectScheduler()->scheduleLocationChange(url.string(), callingFrame->loader()->outgoingReferrer(), lockHistory, lockBackForwardList, processingUserGesture()); 126 } 127 128 ScriptExecutionContext* getScriptExecutionContext(ScriptState* scriptState) 129 { 130 #if ENABLE(WORKERS) 131 WorkerContextExecutionProxy* proxy = WorkerContextExecutionProxy::retrieve(); 132 if (proxy) 133 return proxy->workerContext()->scriptExecutionContext(); 134 #endif 135 136 Frame* frame; 137 if (scriptState) { 138 v8::HandleScope handleScope; 139 frame = V8Proxy::retrieveFrame(scriptState->context()); 140 } else 141 frame = V8Proxy::retrieveFrameForCurrentContext(); 142 143 if (frame) 144 return frame->document()->scriptExecutionContext(); 145 146 return 0; 147 } 148 149 void reportException(ScriptState* scriptState, v8::TryCatch& exceptionCatcher) 150 { 151 String errorMessage; 152 int lineNumber = 0; 153 String sourceURL; 154 155 // There can be a situation that an exception is thrown without setting a message. 156 v8::Local<v8::Message> message = exceptionCatcher.Message(); 157 if (message.IsEmpty()) { 158 v8::Local<v8::String> exceptionString = exceptionCatcher.Exception()->ToString(); 159 // Conversion of the exception object to string can fail if an 160 // exception is thrown during conversion. 161 if (!exceptionString.IsEmpty()) 162 errorMessage = toWebCoreString(exceptionString); 163 } else { 164 errorMessage = toWebCoreString(message->Get()); 165 lineNumber = message->GetLineNumber(); 166 sourceURL = toWebCoreString(message->GetScriptResourceName()); 167 } 168 169 // Do not report the exception if the current execution context is Document because we do not want to lead to duplicate error messages in the console. 170 // FIXME (31171): need better design to solve the duplicate error message reporting problem. 171 ScriptExecutionContext* context = getScriptExecutionContext(scriptState); 172 // During the frame teardown, there may not be a valid context. 173 if (context && !context->isDocument()) 174 context->reportException(errorMessage, lineNumber, sourceURL); 175 exceptionCatcher.Reset(); 176 } 177 178 } // namespace WebCore 179