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 "V8Proxy.h" 33 34 #include "CSSMutableStyleDeclaration.h" 35 #include "CachedMetadata.h" 36 #include "DateExtension.h" 37 #include "DocumentLoader.h" 38 #include "Frame.h" 39 #include "FrameLoaderClient.h" 40 #include "IDBDatabaseException.h" 41 #include "IDBFactoryBackendInterface.h" 42 #include "IDBPendingTransactionMonitor.h" 43 #include "InspectorInstrumentation.h" 44 #include "Page.h" 45 #include "PageGroup.h" 46 #include "PlatformBridge.h" 47 #include "ScriptController.h" 48 #include "Settings.h" 49 #include "StorageNamespace.h" 50 #include "V8Binding.h" 51 #include "V8BindingState.h" 52 #include "V8Collection.h" 53 #include "V8DOMCoreException.h" 54 #include "V8DOMMap.h" 55 #include "V8DOMWindow.h" 56 #include "V8EventException.h" 57 #include "V8FileException.h" 58 #include "V8HiddenPropertyName.h" 59 #include "V8IsolatedContext.h" 60 #include "V8RangeException.h" 61 #include "V8SQLException.h" 62 #include "V8XMLHttpRequestException.h" 63 #include "V8XPathException.h" 64 #include "WorkerContext.h" 65 #include "WorkerContextExecutionProxy.h" 66 67 #if ENABLE(INDEXED_DATABASE) 68 #include "V8IDBDatabaseException.h" 69 #endif 70 71 #if ENABLE(SVG) 72 #include "V8SVGException.h" 73 #endif 74 75 #include <algorithm> 76 #include <stdio.h> 77 #include <utility> 78 #include <wtf/Assertions.h> 79 #include <wtf/OwnArrayPtr.h> 80 #include <wtf/OwnPtr.h> 81 #include <wtf/StdLibExtras.h> 82 #include <wtf/StringExtras.h> 83 #include <wtf/UnusedParam.h> 84 #include <wtf/text/StringConcatenate.h> 85 86 namespace WebCore { 87 88 // Static list of registered extensions 89 V8Extensions V8Proxy::m_extensions; 90 91 void batchConfigureAttributes(v8::Handle<v8::ObjectTemplate> instance, 92 v8::Handle<v8::ObjectTemplate> proto, 93 const BatchedAttribute* attributes, 94 size_t attributeCount) 95 { 96 for (size_t i = 0; i < attributeCount; ++i) 97 configureAttribute(instance, proto, attributes[i]); 98 } 99 100 void batchConfigureCallbacks(v8::Handle<v8::ObjectTemplate> proto, 101 v8::Handle<v8::Signature> signature, 102 v8::PropertyAttribute attributes, 103 const BatchedCallback* callbacks, 104 size_t callbackCount) 105 { 106 for (size_t i = 0; i < callbackCount; ++i) { 107 proto->Set(v8::String::New(callbacks[i].name), 108 v8::FunctionTemplate::New(callbacks[i].callback, 109 v8::Handle<v8::Value>(), 110 signature), 111 attributes); 112 } 113 } 114 115 void batchConfigureConstants(v8::Handle<v8::FunctionTemplate> functionDescriptor, 116 v8::Handle<v8::ObjectTemplate> proto, 117 const BatchedConstant* constants, 118 size_t constantCount) 119 { 120 for (size_t i = 0; i < constantCount; ++i) { 121 const BatchedConstant* constant = &constants[i]; 122 functionDescriptor->Set(v8::String::New(constant->name), v8::Integer::New(constant->value), v8::ReadOnly); 123 proto->Set(v8::String::New(constant->name), v8::Integer::New(constant->value), v8::ReadOnly); 124 } 125 } 126 127 typedef HashMap<Node*, v8::Object*> DOMNodeMap; 128 typedef HashMap<void*, v8::Object*> DOMObjectMap; 129 typedef HashMap<int, v8::FunctionTemplate*> FunctionTemplateMap; 130 131 bool AllowAllocation::m_current = false; 132 133 static void addMessageToConsole(Page* page, const String& message, const String& sourceID, unsigned lineNumber) 134 { 135 ASSERT(page); 136 Console* console = page->mainFrame()->domWindow()->console(); 137 console->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, message, lineNumber, sourceID); 138 } 139 140 void logInfo(Frame* frame, const String& message, const String& url) 141 { 142 Page* page = frame->page(); 143 if (!page) 144 return; 145 addMessageToConsole(page, message, url, 0); 146 } 147 148 void V8Proxy::reportUnsafeAccessTo(Frame* target) 149 { 150 ASSERT(target); 151 Document* targetDocument = target->document(); 152 if (!targetDocument) 153 return; 154 155 Frame* source = V8Proxy::retrieveFrameForEnteredContext(); 156 if (!source) 157 return; 158 Page* page = source->page(); 159 if (!page) 160 return; 161 162 Document* sourceDocument = source->document(); 163 if (!sourceDocument) 164 return; // Ignore error if the source document is gone. 165 166 // FIXME: This error message should contain more specifics of why the same 167 // origin check has failed. 168 String str = makeString("Unsafe JavaScript attempt to access frame with URL ", targetDocument->url().string(), 169 " from frame with URL ", sourceDocument->url().string(), ". Domains, protocols and ports must match.\n"); 170 171 // Build a console message with fake source ID and line number. 172 const String kSourceID = ""; 173 const int kLineNumber = 1; 174 175 // NOTE: Safari prints the message in the target page, but it seems like 176 // it should be in the source page. Even for delayed messages, we put it in 177 // the source page. 178 addMessageToConsole(page, str, kSourceID, kLineNumber); 179 } 180 181 static void handleFatalErrorInV8() 182 { 183 // FIXME: We temporarily deal with V8 internal error situations 184 // such as out-of-memory by crashing the renderer. 185 CRASH(); 186 } 187 188 V8Proxy::V8Proxy(Frame* frame) 189 : m_frame(frame) 190 , m_windowShell(V8DOMWindowShell::create(frame)) 191 , m_inlineCode(false) 192 , m_timerCallback(false) 193 , m_recursion(0) 194 { 195 } 196 197 V8Proxy::~V8Proxy() 198 { 199 clearForClose(); 200 windowShell()->destroyGlobal(); 201 } 202 203 v8::Handle<v8::Script> V8Proxy::compileScript(v8::Handle<v8::String> code, const String& fileName, const TextPosition0& scriptStartPosition, v8::ScriptData* scriptData) 204 { 205 const uint16_t* fileNameString = fromWebCoreString(fileName); 206 v8::Handle<v8::String> name = v8::String::New(fileNameString, fileName.length()); 207 v8::Handle<v8::Integer> line = v8::Integer::New(scriptStartPosition.m_line.zeroBasedInt()); 208 v8::Handle<v8::Integer> column = v8::Integer::New(scriptStartPosition.m_column.zeroBasedInt()); 209 v8::ScriptOrigin origin(name, line, column); 210 v8::Handle<v8::Script> script = v8::Script::Compile(code, &origin, scriptData); 211 return script; 212 } 213 214 bool V8Proxy::handleOutOfMemory() 215 { 216 v8::Local<v8::Context> context = v8::Context::GetCurrent(); 217 218 if (!context->HasOutOfMemoryException()) 219 return false; 220 221 // Warning, error, disable JS for this frame? 222 Frame* frame = V8Proxy::retrieveFrame(context); 223 224 V8Proxy* proxy = V8Proxy::retrieve(frame); 225 if (proxy) { 226 // Clean m_context, and event handlers. 227 proxy->clearForClose(); 228 229 proxy->windowShell()->destroyGlobal(); 230 } 231 232 #if PLATFORM(CHROMIUM) 233 PlatformBridge::notifyJSOutOfMemory(frame); 234 #endif 235 236 // Disable JS. 237 Settings* settings = frame->settings(); 238 ASSERT(settings); 239 settings->setJavaScriptEnabled(false); 240 241 return true; 242 } 243 244 void V8Proxy::evaluateInIsolatedWorld(int worldID, const Vector<ScriptSourceCode>& sources, int extensionGroup) 245 { 246 // FIXME: This will need to get reorganized once we have a windowShell for the isolated world. 247 windowShell()->initContextIfNeeded(); 248 249 v8::HandleScope handleScope; 250 V8IsolatedContext* isolatedContext = 0; 251 252 if (worldID > 0) { 253 IsolatedWorldMap::iterator iter = m_isolatedWorlds.find(worldID); 254 if (iter != m_isolatedWorlds.end()) { 255 isolatedContext = iter->second; 256 } else { 257 isolatedContext = new V8IsolatedContext(this, extensionGroup); 258 if (isolatedContext->context().IsEmpty()) { 259 delete isolatedContext; 260 return; 261 } 262 263 // FIXME: We should change this to using window shells to match JSC. 264 m_isolatedWorlds.set(worldID, isolatedContext); 265 266 // Setup context id for JS debugger. 267 if (!setInjectedScriptContextDebugId(isolatedContext->context())) { 268 m_isolatedWorlds.take(worldID); 269 delete isolatedContext; 270 return; 271 } 272 } 273 } else { 274 isolatedContext = new V8IsolatedContext(this, extensionGroup); 275 if (isolatedContext->context().IsEmpty()) { 276 delete isolatedContext; 277 return; 278 } 279 } 280 281 v8::Local<v8::Context> context = v8::Local<v8::Context>::New(isolatedContext->context()); 282 v8::Context::Scope context_scope(context); 283 for (size_t i = 0; i < sources.size(); ++i) 284 evaluate(sources[i], 0); 285 286 if (worldID == 0) 287 isolatedContext->destroy(); 288 } 289 290 bool V8Proxy::setInjectedScriptContextDebugId(v8::Handle<v8::Context> targetContext) 291 { 292 // Setup context id for JS debugger. 293 v8::Context::Scope contextScope(targetContext); 294 v8::Handle<v8::Context> context = windowShell()->context(); 295 if (context.IsEmpty()) 296 return false; 297 int debugId = contextDebugId(context); 298 299 char buffer[32]; 300 if (debugId == -1) 301 snprintf(buffer, sizeof(buffer), "injected"); 302 else 303 snprintf(buffer, sizeof(buffer), "injected,%d", debugId); 304 targetContext->SetData(v8::String::New(buffer)); 305 306 return true; 307 } 308 309 PassOwnPtr<v8::ScriptData> V8Proxy::precompileScript(v8::Handle<v8::String> code, CachedScript* cachedScript) 310 { 311 // A pseudo-randomly chosen ID used to store and retrieve V8 ScriptData from 312 // the CachedScript. If the format changes, this ID should be changed too. 313 static const unsigned dataTypeID = 0xECC13BD7; 314 315 // Very small scripts are not worth the effort to preparse. 316 static const int minPreparseLength = 1024; 317 318 if (!cachedScript || code->Length() < minPreparseLength) 319 return 0; 320 321 CachedMetadata* cachedMetadata = cachedScript->cachedMetadata(dataTypeID); 322 if (cachedMetadata) 323 return v8::ScriptData::New(cachedMetadata->data(), cachedMetadata->size()); 324 325 OwnPtr<v8::ScriptData> scriptData(v8::ScriptData::PreCompile(code)); 326 cachedScript->setCachedMetadata(dataTypeID, scriptData->Data(), scriptData->Length()); 327 328 return scriptData.release(); 329 } 330 331 bool V8Proxy::executingScript() const 332 { 333 return m_recursion; 334 } 335 336 v8::Local<v8::Value> V8Proxy::evaluate(const ScriptSourceCode& source, Node* node) 337 { 338 ASSERT(v8::Context::InContext()); 339 340 V8GCController::checkMemoryUsage(); 341 342 InspectorInstrumentationCookie cookie = InspectorInstrumentation::willEvaluateScript(m_frame, source.url().isNull() ? String() : source.url().string(), source.startLine()); 343 344 v8::Local<v8::Value> result; 345 { 346 // Isolate exceptions that occur when compiling and executing 347 // the code. These exceptions should not interfere with 348 // javascript code we might evaluate from C++ when returning 349 // from here. 350 v8::TryCatch tryCatch; 351 tryCatch.SetVerbose(true); 352 353 // Compile the script. 354 v8::Local<v8::String> code = v8ExternalString(source.source()); 355 #if PLATFORM(CHROMIUM) 356 PlatformBridge::traceEventBegin("v8.compile", node, ""); 357 #endif 358 OwnPtr<v8::ScriptData> scriptData = precompileScript(code, source.cachedScript()); 359 360 // NOTE: For compatibility with WebCore, ScriptSourceCode's line starts at 361 // 1, whereas v8 starts at 0. 362 v8::Handle<v8::Script> script = compileScript(code, source.url(), WTF::toZeroBasedTextPosition(source.startPosition()), scriptData.get()); 363 #if PLATFORM(CHROMIUM) 364 PlatformBridge::traceEventEnd("v8.compile", node, ""); 365 366 PlatformBridge::traceEventBegin("v8.run", node, ""); 367 #endif 368 // Set inlineCode to true for <a href="javascript:doSomething()"> 369 // and false for <script>doSomething</script>. We make a rough guess at 370 // this based on whether the script source has a URL. 371 result = runScript(script, source.url().string().isNull()); 372 } 373 #if PLATFORM(CHROMIUM) 374 PlatformBridge::traceEventEnd("v8.run", node, ""); 375 #endif 376 377 InspectorInstrumentation::didEvaluateScript(cookie); 378 379 return result; 380 } 381 382 v8::Local<v8::Value> V8Proxy::runScript(v8::Handle<v8::Script> script, bool isInlineCode) 383 { 384 if (script.IsEmpty()) 385 return notHandledByInterceptor(); 386 387 V8GCController::checkMemoryUsage(); 388 // Compute the source string and prevent against infinite recursion. 389 if (m_recursion >= kMaxRecursionDepth) { 390 v8::Local<v8::String> code = v8ExternalString("throw RangeError('Recursion too deep')"); 391 // FIXME: Ideally, we should be able to re-use the origin of the 392 // script passed to us as the argument instead of using an empty string 393 // and 0 baseLine. 394 script = compileScript(code, "", TextPosition0::minimumPosition()); 395 } 396 397 if (handleOutOfMemory()) 398 ASSERT(script.IsEmpty()); 399 400 if (script.IsEmpty()) 401 return notHandledByInterceptor(); 402 403 // Save the previous value of the inlineCode flag and update the flag for 404 // the duration of the script invocation. 405 bool previousInlineCode = inlineCode(); 406 setInlineCode(isInlineCode); 407 408 // Run the script and keep track of the current recursion depth. 409 v8::Local<v8::Value> result; 410 v8::TryCatch tryCatch; 411 tryCatch.SetVerbose(true); 412 { 413 // See comment in V8Proxy::callFunction. 414 m_frame->keepAlive(); 415 416 m_recursion++; 417 result = script->Run(); 418 m_recursion--; 419 } 420 421 // Release the storage mutex if applicable. 422 didLeaveScriptContext(); 423 424 if (handleOutOfMemory()) 425 ASSERT(result.IsEmpty()); 426 427 // Handle V8 internal error situation (Out-of-memory). 428 if (tryCatch.HasCaught()) { 429 ASSERT(result.IsEmpty()); 430 return notHandledByInterceptor(); 431 } 432 433 if (result.IsEmpty()) 434 return notHandledByInterceptor(); 435 436 // Restore inlineCode flag. 437 setInlineCode(previousInlineCode); 438 439 if (v8::V8::IsDead()) 440 handleFatalErrorInV8(); 441 442 return result; 443 } 444 445 v8::Local<v8::Value> V8Proxy::callFunction(v8::Handle<v8::Function> function, v8::Handle<v8::Object> receiver, int argc, v8::Handle<v8::Value> args[]) 446 { 447 V8GCController::checkMemoryUsage(); 448 v8::Local<v8::Value> result; 449 { 450 if (m_recursion >= kMaxRecursionDepth) { 451 v8::Local<v8::String> code = v8::String::New("throw new RangeError('Maximum call stack size exceeded.')"); 452 if (code.IsEmpty()) 453 return result; 454 v8::Local<v8::Script> script = v8::Script::Compile(code); 455 if (script.IsEmpty()) 456 return result; 457 script->Run(); 458 return result; 459 } 460 461 // Evaluating the JavaScript could cause the frame to be deallocated, 462 // so we start the keep alive timer here. 463 // Frame::keepAlive method adds the ref count of the frame and sets a 464 // timer to decrease the ref count. It assumes that the current JavaScript 465 // execution finishs before firing the timer. 466 m_frame->keepAlive(); 467 468 InspectorInstrumentationCookie cookie; 469 if (InspectorInstrumentation::hasFrontends()) { 470 v8::ScriptOrigin origin = function->GetScriptOrigin(); 471 String resourceName("undefined"); 472 int lineNumber = 1; 473 if (!origin.ResourceName().IsEmpty()) { 474 resourceName = toWebCoreString(origin.ResourceName()); 475 lineNumber = function->GetScriptLineNumber() + 1; 476 } 477 cookie = InspectorInstrumentation::willCallFunction(m_frame, resourceName, lineNumber); 478 } 479 480 m_recursion++; 481 result = function->Call(receiver, argc, args); 482 m_recursion--; 483 484 InspectorInstrumentation::didCallFunction(cookie); 485 } 486 487 // Release the storage mutex if applicable. 488 didLeaveScriptContext(); 489 490 if (v8::V8::IsDead()) 491 handleFatalErrorInV8(); 492 493 return result; 494 } 495 496 v8::Local<v8::Value> V8Proxy::callFunctionWithoutFrame(v8::Handle<v8::Function> function, v8::Handle<v8::Object> receiver, int argc, v8::Handle<v8::Value> args[]) 497 { 498 V8GCController::checkMemoryUsage(); 499 v8::Local<v8::Value> result = function->Call(receiver, argc, args); 500 501 if (v8::V8::IsDead()) 502 handleFatalErrorInV8(); 503 504 return result; 505 } 506 507 v8::Local<v8::Value> V8Proxy::newInstance(v8::Handle<v8::Function> constructor, int argc, v8::Handle<v8::Value> args[]) 508 { 509 // No artificial limitations on the depth of recursion, see comment in 510 // V8Proxy::callFunction. 511 v8::Local<v8::Value> result; 512 { 513 // See comment in V8Proxy::callFunction. 514 m_frame->keepAlive(); 515 516 result = constructor->NewInstance(argc, args); 517 } 518 519 if (v8::V8::IsDead()) 520 handleFatalErrorInV8(); 521 522 return result; 523 } 524 525 DOMWindow* V8Proxy::retrieveWindow(v8::Handle<v8::Context> context) 526 { 527 v8::Handle<v8::Object> global = context->Global(); 528 ASSERT(!global.IsEmpty()); 529 global = V8DOMWrapper::lookupDOMWrapper(V8DOMWindow::GetTemplate(), global); 530 ASSERT(!global.IsEmpty()); 531 return V8DOMWindow::toNative(global); 532 } 533 534 Frame* V8Proxy::retrieveFrame(v8::Handle<v8::Context> context) 535 { 536 DOMWindow* window = retrieveWindow(context); 537 Frame* frame = window->frame(); 538 if (frame && frame->domWindow() == window) 539 return frame; 540 // We return 0 here because |context| is detached from the Frame. If we 541 // did return |frame| we could get in trouble because the frame could be 542 // navigated to another security origin. 543 return 0; 544 } 545 546 Frame* V8Proxy::retrieveFrameForEnteredContext() 547 { 548 v8::Handle<v8::Context> context = v8::Context::GetEntered(); 549 if (context.IsEmpty()) 550 return 0; 551 return retrieveFrame(context); 552 } 553 554 Frame* V8Proxy::retrieveFrameForCurrentContext() 555 { 556 v8::Handle<v8::Context> context = v8::Context::GetCurrent(); 557 if (context.IsEmpty()) 558 return 0; 559 return retrieveFrame(context); 560 } 561 562 Frame* V8Proxy::retrieveFrameForCallingContext() 563 { 564 v8::Handle<v8::Context> context = v8::Context::GetCalling(); 565 if (context.IsEmpty()) 566 return 0; 567 return retrieveFrame(context); 568 } 569 570 V8Proxy* V8Proxy::retrieve() 571 { 572 DOMWindow* window = retrieveWindow(currentContext()); 573 ASSERT(window); 574 return retrieve(window->frame()); 575 } 576 577 V8Proxy* V8Proxy::retrieve(Frame* frame) 578 { 579 if (!frame) 580 return 0; 581 return frame->script()->canExecuteScripts(NotAboutToExecuteScript) ? frame->script()->proxy() : 0; 582 } 583 584 V8Proxy* V8Proxy::retrieve(ScriptExecutionContext* context) 585 { 586 if (!context || !context->isDocument()) 587 return 0; 588 return retrieve(static_cast<Document*>(context)->frame()); 589 } 590 591 void V8Proxy::disconnectFrame() 592 { 593 } 594 595 void V8Proxy::didLeaveScriptContext() 596 { 597 Page* page = m_frame->page(); 598 if (!page) 599 return; 600 #if ENABLE(INDEXED_DATABASE) 601 // If we've just left a script context and indexed database has been 602 // instantiated, we must let its transaction coordinator know so it can terminate 603 // any not-yet-started transactions. 604 IDBPendingTransactionMonitor::abortPendingTransactions(); 605 #endif // ENABLE(INDEXED_DATABASE) 606 // If we've just left a top level script context and local storage has been 607 // instantiated, we must ensure that any storage locks have been freed. 608 // Per http://dev.w3.org/html5/spec/Overview.html#storage-mutex 609 if (m_recursion != 0) 610 return; 611 if (page->group().hasLocalStorage()) 612 page->group().localStorage()->unlock(); 613 } 614 615 void V8Proxy::resetIsolatedWorlds() 616 { 617 for (IsolatedWorldMap::iterator iter = m_isolatedWorlds.begin(); 618 iter != m_isolatedWorlds.end(); ++iter) { 619 iter->second->destroy(); 620 } 621 m_isolatedWorlds.clear(); 622 } 623 624 void V8Proxy::clearForClose() 625 { 626 resetIsolatedWorlds(); 627 windowShell()->clearForClose(); 628 } 629 630 void V8Proxy::clearForNavigation() 631 { 632 resetIsolatedWorlds(); 633 windowShell()->clearForNavigation(); 634 } 635 636 void V8Proxy::setDOMException(int exceptionCode) 637 { 638 if (exceptionCode <= 0) 639 return; 640 641 ExceptionCodeDescription description; 642 getExceptionCodeDescription(exceptionCode, description); 643 644 v8::Handle<v8::Value> exception; 645 switch (description.type) { 646 case DOMExceptionType: 647 exception = toV8(DOMCoreException::create(description)); 648 break; 649 case RangeExceptionType: 650 exception = toV8(RangeException::create(description)); 651 break; 652 case EventExceptionType: 653 exception = toV8(EventException::create(description)); 654 break; 655 case XMLHttpRequestExceptionType: 656 exception = toV8(XMLHttpRequestException::create(description)); 657 break; 658 #if ENABLE(SVG) 659 case SVGExceptionType: 660 exception = toV8(SVGException::create(description)); 661 break; 662 #endif 663 #if ENABLE(XPATH) 664 case XPathExceptionType: 665 exception = toV8(XPathException::create(description)); 666 break; 667 #endif 668 #if ENABLE(DATABASE) 669 case SQLExceptionType: 670 exception = toV8(SQLException::create(description)); 671 break; 672 #endif 673 #if ENABLE(BLOB) || ENABLE(FILE_SYSTEM) 674 case FileExceptionType: 675 exception = toV8(FileException::create(description)); 676 break; 677 #endif 678 #if ENABLE(INDEXED_DATABASE) 679 case IDBDatabaseExceptionType: 680 exception = toV8(IDBDatabaseException::create(description)); 681 break; 682 #endif 683 default: 684 ASSERT_NOT_REACHED(); 685 } 686 687 if (!exception.IsEmpty()) 688 v8::ThrowException(exception); 689 } 690 691 v8::Handle<v8::Value> V8Proxy::throwError(ErrorType type, const char* message) 692 { 693 switch (type) { 694 case RangeError: 695 return v8::ThrowException(v8::Exception::RangeError(v8String(message))); 696 case ReferenceError: 697 return v8::ThrowException(v8::Exception::ReferenceError(v8String(message))); 698 case SyntaxError: 699 return v8::ThrowException(v8::Exception::SyntaxError(v8String(message))); 700 case TypeError: 701 return v8::ThrowException(v8::Exception::TypeError(v8String(message))); 702 case GeneralError: 703 return v8::ThrowException(v8::Exception::Error(v8String(message))); 704 default: 705 ASSERT_NOT_REACHED(); 706 return notHandledByInterceptor(); 707 } 708 } 709 710 v8::Handle<v8::Value> V8Proxy::throwTypeError() 711 { 712 return throwError(TypeError, "Type error"); 713 } 714 715 v8::Handle<v8::Value> V8Proxy::throwSyntaxError() 716 { 717 return throwError(SyntaxError, "Syntax error"); 718 } 719 720 v8::Local<v8::Context> V8Proxy::context(Frame* frame) 721 { 722 v8::Local<v8::Context> context = V8Proxy::mainWorldContext(frame); 723 if (context.IsEmpty()) 724 return v8::Local<v8::Context>(); 725 726 if (V8IsolatedContext* isolatedContext = V8IsolatedContext::getEntered()) { 727 context = v8::Local<v8::Context>::New(isolatedContext->context()); 728 if (frame != V8Proxy::retrieveFrame(context)) 729 return v8::Local<v8::Context>(); 730 } 731 732 return context; 733 } 734 735 v8::Local<v8::Context> V8Proxy::context() 736 { 737 if (V8IsolatedContext* isolatedContext = V8IsolatedContext::getEntered()) { 738 RefPtr<SharedPersistent<v8::Context> > context = isolatedContext->sharedContext(); 739 if (m_frame != V8Proxy::retrieveFrame(context->get())) 740 return v8::Local<v8::Context>(); 741 return v8::Local<v8::Context>::New(context->get()); 742 } 743 return mainWorldContext(); 744 } 745 746 v8::Local<v8::Context> V8Proxy::mainWorldContext() 747 { 748 windowShell()->initContextIfNeeded(); 749 return v8::Local<v8::Context>::New(windowShell()->context()); 750 } 751 752 v8::Local<v8::Context> V8Proxy::mainWorldContext(Frame* frame) 753 { 754 V8Proxy* proxy = retrieve(frame); 755 if (!proxy) 756 return v8::Local<v8::Context>(); 757 758 return proxy->mainWorldContext(); 759 } 760 761 v8::Local<v8::Context> V8Proxy::currentContext() 762 { 763 return v8::Context::GetCurrent(); 764 } 765 766 v8::Handle<v8::Value> V8Proxy::checkNewLegal(const v8::Arguments& args) 767 { 768 if (!AllowAllocation::m_current) 769 return throwError(TypeError, "Illegal constructor"); 770 771 return args.This(); 772 } 773 774 void V8Proxy::registerExtensionWithV8(v8::Extension* extension) 775 { 776 // If the extension exists in our list, it was already registered with V8. 777 if (!registeredExtensionWithV8(extension)) 778 v8::RegisterExtension(extension); 779 } 780 781 bool V8Proxy::registeredExtensionWithV8(v8::Extension* extension) 782 { 783 for (size_t i = 0; i < m_extensions.size(); ++i) { 784 if (m_extensions[i] == extension) 785 return true; 786 } 787 788 return false; 789 } 790 791 void V8Proxy::registerExtension(v8::Extension* extension) 792 { 793 registerExtensionWithV8(extension); 794 m_extensions.append(extension); 795 } 796 797 bool V8Proxy::setContextDebugId(int debugId) 798 { 799 ASSERT(debugId > 0); 800 v8::HandleScope scope; 801 v8::Handle<v8::Context> context = windowShell()->context(); 802 if (context.IsEmpty()) 803 return false; 804 if (!context->GetData()->IsUndefined()) 805 return false; 806 807 v8::Context::Scope contextScope(context); 808 809 char buffer[32]; 810 snprintf(buffer, sizeof(buffer), "page,%d", debugId); 811 context->SetData(v8::String::New(buffer)); 812 813 return true; 814 } 815 816 int V8Proxy::contextDebugId(v8::Handle<v8::Context> context) 817 { 818 v8::HandleScope scope; 819 if (!context->GetData()->IsString()) 820 return -1; 821 v8::String::AsciiValue ascii(context->GetData()); 822 char* comma = strnstr(*ascii, ",", ascii.length()); 823 if (!comma) 824 return -1; 825 return atoi(comma + 1); 826 } 827 828 v8::Local<v8::Context> toV8Context(ScriptExecutionContext* context, const WorldContextHandle& worldContext) 829 { 830 if (context->isDocument()) { 831 if (V8Proxy* proxy = V8Proxy::retrieve(context)) 832 return worldContext.adjustedContext(proxy); 833 #if ENABLE(WORKERS) 834 } else if (context->isWorkerContext()) { 835 if (WorkerContextExecutionProxy* proxy = static_cast<WorkerContext*>(context)->script()->proxy()) 836 return proxy->context(); 837 #endif 838 } 839 return v8::Local<v8::Context>(); 840 } 841 842 } // namespace WebCore 843