1/* 2 * Copyright (C) 2008, 2009, 2010 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 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#if USE(PLUGIN_HOST_PROCESS) && ENABLE(NETSCAPE_PLUGIN_API) 27 28#import "NetscapePluginInstanceProxy.h" 29 30#import "HostedNetscapePluginStream.h" 31#import "NetscapePluginHostProxy.h" 32#import "ProxyInstance.h" 33#import "ProxyRuntimeObject.h" 34#import "WebDataSourceInternal.h" 35#import "WebFrameInternal.h" 36#import "WebHostedNetscapePluginView.h" 37#import "WebKitNSStringExtras.h" 38#import "WebNSDataExtras.h" 39#import "WebNSURLExtras.h" 40#import "WebPluginRequest.h" 41#import "WebUIDelegate.h" 42#import "WebUIDelegatePrivate.h" 43#import "WebViewInternal.h" 44#import <JavaScriptCore/Completion.h> 45#import <JavaScriptCore/Error.h> 46#import <JavaScriptCore/JSLock.h> 47#import <JavaScriptCore/PropertyNameArray.h> 48#import <JavaScriptCore/SourceCode.h> 49#import <JavaScriptCore/StrongInlines.h> 50#import <WebCore/CookieJar.h> 51#import <WebCore/Document.h> 52#import <WebCore/DocumentLoader.h> 53#import <WebCore/Frame.h> 54#import <WebCore/FrameLoader.h> 55#import <WebCore/FrameTree.h> 56#import <WebCore/URL.h> 57#import <WebCore/ProxyServer.h> 58#import <WebCore/SecurityOrigin.h> 59#import <WebCore/ScriptController.h> 60#import <WebCore/UserGestureIndicator.h> 61#import <WebCore/npruntime_impl.h> 62#import <WebCore/runtime_object.h> 63#import <WebKitSystemInterface.h> 64#import <bindings/ScriptValue.h> 65#import <mach/mach.h> 66#import <utility> 67#import <wtf/RefCountedLeakCounter.h> 68#import <wtf/text/CString.h> 69 70extern "C" { 71#import "WebKitPluginClientServer.h" 72#import "WebKitPluginHost.h" 73} 74 75using namespace JSC; 76using namespace JSC::Bindings; 77using namespace WebCore; 78 79namespace WebKit { 80 81class NetscapePluginInstanceProxy::PluginRequest : public RefCounted<NetscapePluginInstanceProxy::PluginRequest> { 82public: 83 static PassRefPtr<PluginRequest> create(uint32_t requestID, NSURLRequest* request, NSString* frameName, bool allowPopups) 84 { 85 return adoptRef(new PluginRequest(requestID, request, frameName, allowPopups)); 86 } 87 88 uint32_t requestID() const { return m_requestID; } 89 NSURLRequest* request() const { return m_request.get(); } 90 NSString* frameName() const { return m_frameName.get(); } 91 bool allowPopups() const { return m_allowPopups; } 92 93private: 94 PluginRequest(uint32_t requestID, NSURLRequest* request, NSString* frameName, bool allowPopups) 95 : m_requestID(requestID) 96 , m_request(request) 97 , m_frameName(frameName) 98 , m_allowPopups(allowPopups) 99 { 100 } 101 102 uint32_t m_requestID; 103 RetainPtr<NSURLRequest*> m_request; 104 RetainPtr<NSString*> m_frameName; 105 bool m_allowPopups; 106}; 107 108NetscapePluginInstanceProxy::LocalObjectMap::LocalObjectMap() 109 : m_objectIDCounter(0) 110{ 111} 112 113NetscapePluginInstanceProxy::LocalObjectMap::~LocalObjectMap() 114{ 115} 116 117inline bool NetscapePluginInstanceProxy::LocalObjectMap::contains(uint32_t objectID) const 118{ 119 return m_idToJSObjectMap.contains(objectID); 120} 121 122inline JSC::JSObject* NetscapePluginInstanceProxy::LocalObjectMap::get(uint32_t objectID) const 123{ 124 if (objectID == HashTraits<uint32_t>::emptyValue() || HashTraits<uint32_t>::isDeletedValue(objectID)) 125 return nullptr; 126 127 return m_idToJSObjectMap.get(objectID).get(); 128} 129 130uint32_t NetscapePluginInstanceProxy::LocalObjectMap::idForObject(VM& vm, JSObject* object) 131{ 132 // This method creates objects with refcount of 1, but doesn't increase refcount when returning 133 // found objects. This extra count accounts for the main "reference" kept by plugin process. 134 135 // To avoid excessive IPC, plugin process doesn't send each NPObject release/retain call to 136 // Safari. It only sends one when the last reference is removed, and it can destroy the proxy 137 // NPObject. 138 139 // However, the browser may be sending the same object out to plug-in as a function call 140 // argument at the same time - neither side can know what the other one is doing. So, 141 // is to make PCForgetBrowserObject call return a boolean result, making it possible for 142 // the browser to make plugin host keep the proxy with zero refcount for a little longer. 143 144 uint32_t objectID = 0; 145 146 HashMap<JSC::JSObject*, std::pair<uint32_t, uint32_t>>::iterator iter = m_jsObjectToIDMap.find(object); 147 if (iter != m_jsObjectToIDMap.end()) 148 return iter->value.first; 149 150 do { 151 objectID = ++m_objectIDCounter; 152 } while (!m_objectIDCounter || m_objectIDCounter == static_cast<uint32_t>(-1) || m_idToJSObjectMap.contains(objectID)); 153 154 m_idToJSObjectMap.set(objectID, Strong<JSObject>(vm, object)); 155 m_jsObjectToIDMap.set(object, std::make_pair(objectID, 1)); 156 157 return objectID; 158} 159 160void NetscapePluginInstanceProxy::LocalObjectMap::retain(JSC::JSObject* object) 161{ 162 HashMap<JSC::JSObject*, std::pair<uint32_t, uint32_t>>::iterator iter = m_jsObjectToIDMap.find(object); 163 ASSERT(iter != m_jsObjectToIDMap.end()); 164 165 iter->value.second = iter->value.second + 1; 166} 167 168void NetscapePluginInstanceProxy::LocalObjectMap::release(JSC::JSObject* object) 169{ 170 HashMap<JSC::JSObject*, std::pair<uint32_t, uint32_t>>::iterator iter = m_jsObjectToIDMap.find(object); 171 ASSERT(iter != m_jsObjectToIDMap.end()); 172 173 ASSERT(iter->value.second > 0); 174 iter->value.second = iter->value.second - 1; 175 if (!iter->value.second) { 176 m_idToJSObjectMap.remove(iter->value.first); 177 m_jsObjectToIDMap.remove(iter); 178 } 179} 180 181void NetscapePluginInstanceProxy::LocalObjectMap::clear() 182{ 183 m_idToJSObjectMap.clear(); 184 m_jsObjectToIDMap.clear(); 185} 186 187bool NetscapePluginInstanceProxy::LocalObjectMap::forget(uint32_t objectID) 188{ 189 if (objectID == HashTraits<uint32_t>::emptyValue() || HashTraits<uint32_t>::isDeletedValue(objectID)) { 190 LOG_ERROR("NetscapePluginInstanceProxy::LocalObjectMap::forget: local object id %u is not valid.", objectID); 191 return true; 192 } 193 194 HashMap<uint32_t, JSC::Strong<JSC::JSObject>>::iterator iter = m_idToJSObjectMap.find(objectID); 195 if (iter == m_idToJSObjectMap.end()) { 196 LOG_ERROR("NetscapePluginInstanceProxy::LocalObjectMap::forget: local object %u doesn't exist.", objectID); 197 return true; 198 } 199 200 HashMap<JSC::JSObject*, std::pair<uint32_t, uint32_t>>::iterator rIter = m_jsObjectToIDMap.find(iter->value.get()); 201 202 // If the object is being sent to plug-in right now, then it's not the time to forget. 203 if (rIter->value.second != 1) 204 return false; 205 206 m_jsObjectToIDMap.remove(rIter); 207 m_idToJSObjectMap.remove(iter); 208 return true; 209} 210 211static uint32_t pluginIDCounter; 212 213bool NetscapePluginInstanceProxy::m_inDestroy; 214 215DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, netscapePluginInstanceProxyCounter, ("NetscapePluginInstanceProxy")); 216 217NetscapePluginInstanceProxy::NetscapePluginInstanceProxy(NetscapePluginHostProxy* pluginHostProxy, WebHostedNetscapePluginView *pluginView, bool fullFramePlugin) 218 : m_pluginHostProxy(pluginHostProxy) 219 , m_pluginView(pluginView) 220 , m_requestTimer(this, &NetscapePluginInstanceProxy::requestTimerFired) 221 , m_currentURLRequestID(0) 222 , m_renderContextID(0) 223 , m_rendererType(UseSoftwareRenderer) 224 , m_waitingForReply(false) 225 , m_urlCheckCounter(0) 226 , m_pluginFunctionCallDepth(0) 227 , m_shouldStopSoon(false) 228 , m_currentRequestID(0) 229 , m_pluginIsWaitingForDraw(false) 230{ 231 ASSERT(m_pluginView); 232 233 if (fullFramePlugin) { 234 // For full frame plug-ins, the first requestID will always be the one for the already 235 // open stream. 236 ++m_currentURLRequestID; 237 } 238 239 // Assign a plug-in ID. 240 do { 241 m_pluginID = ++pluginIDCounter; 242 } while (pluginHostProxy->pluginInstance(m_pluginID) || !m_pluginID); 243 244#ifndef NDEBUG 245 netscapePluginInstanceProxyCounter.increment(); 246#endif 247} 248 249PassRefPtr<NetscapePluginInstanceProxy> NetscapePluginInstanceProxy::create(NetscapePluginHostProxy* pluginHostProxy, WebHostedNetscapePluginView *pluginView, bool fullFramePlugin) 250{ 251 RefPtr<NetscapePluginInstanceProxy> proxy = adoptRef(new NetscapePluginInstanceProxy(pluginHostProxy, pluginView, fullFramePlugin)); 252 pluginHostProxy->addPluginInstance(proxy.get()); 253 return proxy.release(); 254} 255 256NetscapePluginInstanceProxy::~NetscapePluginInstanceProxy() 257{ 258 ASSERT(!m_pluginHostProxy); 259 260 m_pluginID = 0; 261 262#ifndef NDEBUG 263 netscapePluginInstanceProxyCounter.decrement(); 264#endif 265} 266 267void NetscapePluginInstanceProxy::resize(NSRect size, NSRect clipRect) 268{ 269 uint32_t requestID = 0; 270 271 requestID = nextRequestID(); 272 273 _WKPHResizePluginInstance(m_pluginHostProxy->port(), m_pluginID, requestID, 274 size.origin.x, size.origin.y, size.size.width, size.size.height, 275 clipRect.origin.x, clipRect.origin.y, clipRect.size.width, clipRect.size.height); 276 277 waitForReply<NetscapePluginInstanceProxy::BooleanReply>(requestID); 278} 279 280 281void NetscapePluginInstanceProxy::setShouldHostLayersInWindowServer(bool shouldHostLayersInWindowServer) 282{ 283 _WKPHPluginShouldHostLayersInWindowServerChanged(m_pluginHostProxy->port(), m_pluginID, shouldHostLayersInWindowServer); 284} 285 286void NetscapePluginInstanceProxy::layerHostingModeChanged(bool hostsLayersInWindowServer, uint32_t renderContextID) 287{ 288 setRenderContextID(renderContextID); 289 290 [m_pluginView setHostsLayersInWindowServer:hostsLayersInWindowServer]; 291} 292 293void NetscapePluginInstanceProxy::stopAllStreams() 294{ 295 Vector<RefPtr<HostedNetscapePluginStream>> streamsCopy; 296 copyValuesToVector(m_streams, streamsCopy); 297 for (size_t i = 0; i < streamsCopy.size(); i++) 298 streamsCopy[i]->stop(); 299} 300 301void NetscapePluginInstanceProxy::cleanup() 302{ 303 stopAllStreams(); 304 305 m_requestTimer.stop(); 306 307 // Clear the object map, this will cause any outstanding JS objects that the plug-in had a reference to 308 // to go away when the next garbage collection takes place. 309 m_localObjects.clear(); 310 311 if (Frame* frame = core([m_pluginView webFrame])) 312 frame->script().cleanupScriptObjectsForPlugin(m_pluginView); 313 314 ProxyInstanceSet instances; 315 instances.swap(m_instances); 316 317 // Invalidate all proxy instances. 318 ProxyInstanceSet::const_iterator end = instances.end(); 319 for (ProxyInstanceSet::const_iterator it = instances.begin(); it != end; ++it) 320 (*it)->invalidate(); 321 322 m_pluginView = nil; 323 m_manualStream = nullptr; 324} 325 326void NetscapePluginInstanceProxy::invalidate() 327{ 328 // If the plug-in host has died, the proxy will be null. 329 if (!m_pluginHostProxy) 330 return; 331 332 m_pluginHostProxy->removePluginInstance(this); 333 m_pluginHostProxy = nullptr; 334} 335 336void NetscapePluginInstanceProxy::destroy() 337{ 338 uint32_t requestID = nextRequestID(); 339 340 ASSERT(!m_inDestroy); 341 m_inDestroy = true; 342 343 FrameLoadMap::iterator end = m_pendingFrameLoads.end(); 344 for (FrameLoadMap::iterator it = m_pendingFrameLoads.begin(); it != end; ++it) 345 [(it->key) _setInternalLoadDelegate:nil]; 346 347 _WKPHDestroyPluginInstance(m_pluginHostProxy->port(), m_pluginID, requestID); 348 349 // If the plug-in host crashes while we're waiting for a reply, the last reference to the instance proxy 350 // will go away. Prevent this by protecting it here. 351 Ref<NetscapePluginInstanceProxy> protect(*this); 352 353 // We don't care about the reply here - we just want to block until the plug-in instance has been torn down. 354 waitForReply<NetscapePluginInstanceProxy::BooleanReply>(requestID); 355 356 m_inDestroy = false; 357 358 cleanup(); 359 invalidate(); 360} 361 362void NetscapePluginInstanceProxy::setManualStream(PassRefPtr<HostedNetscapePluginStream> manualStream) 363{ 364 ASSERT(!m_manualStream); 365 366 m_manualStream = manualStream; 367} 368 369bool NetscapePluginInstanceProxy::cancelStreamLoad(uint32_t streamID, NPReason reason) 370{ 371 HostedNetscapePluginStream* stream; 372 373 if (m_manualStream && streamID == 1) 374 stream = m_manualStream.get(); 375 else 376 stream = m_streams.get(streamID); 377 378 if (!stream) 379 return false; 380 381 stream->cancelLoad(reason); 382 return true; 383} 384 385void NetscapePluginInstanceProxy::disconnectStream(HostedNetscapePluginStream* stream) 386{ 387 if (stream == m_manualStream) { 388 m_manualStream = nullptr; 389 return; 390 } 391 392 ASSERT(m_streams.get(stream->streamID()) == stream); 393 m_streams.remove(stream->streamID()); 394} 395 396void NetscapePluginInstanceProxy::pluginHostDied() 397{ 398 m_pluginHostProxy = nullptr; 399 400 [m_pluginView pluginHostDied]; 401 402 cleanup(); 403} 404 405void NetscapePluginInstanceProxy::focusChanged(bool hasFocus) 406{ 407 _WKPHPluginInstanceFocusChanged(m_pluginHostProxy->port(), m_pluginID, hasFocus); 408} 409 410void NetscapePluginInstanceProxy::windowFocusChanged(bool hasFocus) 411{ 412 _WKPHPluginInstanceWindowFocusChanged(m_pluginHostProxy->port(), m_pluginID, hasFocus); 413} 414 415void NetscapePluginInstanceProxy::windowFrameChanged(NSRect frame) 416{ 417 _WKPHPluginInstanceWindowFrameChanged(m_pluginHostProxy->port(), m_pluginID, frame.origin.x, frame.origin.y, frame.size.width, frame.size.height, 418 NSMaxY([[[NSScreen screens] objectAtIndex:0] frame])); 419} 420 421void NetscapePluginInstanceProxy::startTimers(bool throttleTimers) 422{ 423 _WKPHPluginInstanceStartTimers(m_pluginHostProxy->port(), m_pluginID, throttleTimers); 424} 425 426void NetscapePluginInstanceProxy::mouseEvent(NSView *pluginView, NSEvent *event, NPCocoaEventType type) 427{ 428#pragma clang diagnostic push 429#pragma clang diagnostic ignored "-Wdeprecated-declarations" 430 NSPoint screenPoint = [[event window] convertBaseToScreen:[event locationInWindow]]; 431#pragma clang diagnostic pop 432 NSPoint pluginPoint = [pluginView convertPoint:[event locationInWindow] fromView:nil]; 433 434 int clickCount; 435 if (type == NPCocoaEventMouseEntered || type == NPCocoaEventMouseExited) 436 clickCount = 0; 437 else 438 clickCount = [event clickCount]; 439 440 441 _WKPHPluginInstanceMouseEvent(m_pluginHostProxy->port(), m_pluginID, 442 [event timestamp], 443 type, [event modifierFlags], 444 pluginPoint.x, pluginPoint.y, 445 screenPoint.x, screenPoint.y, 446 NSMaxY([[[NSScreen screens] objectAtIndex:0] frame]), 447 [event buttonNumber], clickCount, 448 [event deltaX], [event deltaY], [event deltaZ]); 449} 450 451void NetscapePluginInstanceProxy::keyEvent(NSView *pluginView, NSEvent *event, NPCocoaEventType type) 452{ 453 NSData *charactersData = [[event characters] dataUsingEncoding:NSUTF8StringEncoding]; 454 NSData *charactersIgnoringModifiersData = [[event charactersIgnoringModifiers] dataUsingEncoding:NSUTF8StringEncoding]; 455 456 _WKPHPluginInstanceKeyboardEvent(m_pluginHostProxy->port(), m_pluginID, 457 [event timestamp], 458 type, [event modifierFlags], 459 const_cast<char*>(reinterpret_cast<const char*>([charactersData bytes])), [charactersData length], 460 const_cast<char*>(reinterpret_cast<const char*>([charactersIgnoringModifiersData bytes])), [charactersIgnoringModifiersData length], 461 [event isARepeat], [event keyCode], WKGetNSEventKeyChar(event)); 462} 463 464void NetscapePluginInstanceProxy::syntheticKeyDownWithCommandModifier(int keyCode, char character) 465{ 466 NSData *charactersData = [NSData dataWithBytes:&character length:1]; 467 468 _WKPHPluginInstanceKeyboardEvent(m_pluginHostProxy->port(), m_pluginID, 469 [NSDate timeIntervalSinceReferenceDate], 470 NPCocoaEventKeyDown, NSCommandKeyMask, 471 const_cast<char*>(reinterpret_cast<const char*>([charactersData bytes])), [charactersData length], 472 const_cast<char*>(reinterpret_cast<const char*>([charactersData bytes])), [charactersData length], 473 false, keyCode, character); 474} 475 476void NetscapePluginInstanceProxy::flagsChanged(NSEvent *event) 477{ 478 _WKPHPluginInstanceKeyboardEvent(m_pluginHostProxy->port(), m_pluginID, 479 [event timestamp], NPCocoaEventFlagsChanged, 480 [event modifierFlags], 0, 0, 0, 0, false, [event keyCode], 0); 481} 482 483void NetscapePluginInstanceProxy::insertText(NSString *text) 484{ 485 NSData *textData = [text dataUsingEncoding:NSUTF8StringEncoding]; 486 487 _WKPHPluginInstanceInsertText(m_pluginHostProxy->port(), m_pluginID, 488 const_cast<char*>(reinterpret_cast<const char*>([textData bytes])), [textData length]); 489} 490 491bool NetscapePluginInstanceProxy::wheelEvent(NSView *pluginView, NSEvent *event) 492{ 493 NSPoint pluginPoint = [pluginView convertPoint:[event locationInWindow] fromView:nil]; 494 495 uint32_t requestID = nextRequestID(); 496 _WKPHPluginInstanceWheelEvent(m_pluginHostProxy->port(), m_pluginID, requestID, 497 [event timestamp], [event modifierFlags], 498 pluginPoint.x, pluginPoint.y, [event buttonNumber], 499 [event deltaX], [event deltaY], [event deltaZ]); 500 501 auto reply = waitForReply<NetscapePluginInstanceProxy::BooleanReply>(requestID); 502 return reply && reply->m_result; 503} 504 505void NetscapePluginInstanceProxy::print(CGContextRef context, unsigned width, unsigned height) 506{ 507 uint32_t requestID = nextRequestID(); 508 _WKPHPluginInstancePrint(m_pluginHostProxy->port(), m_pluginID, requestID, width, height); 509 510 auto reply = waitForReply<NetscapePluginInstanceProxy::BooleanAndDataReply>(requestID); 511 if (!reply || !reply->m_returnValue) 512 return; 513 514 RetainPtr<CGDataProvider> dataProvider = adoptCF(CGDataProviderCreateWithCFData(reply->m_result.get())); 515 RetainPtr<CGColorSpaceRef> colorSpace = adoptCF(CGColorSpaceCreateDeviceRGB()); 516 RetainPtr<CGImageRef> image = adoptCF(CGImageCreate(width, height, 8, 32, width * 4, colorSpace.get(), kCGImageAlphaFirst, dataProvider.get(), 0, false, kCGRenderingIntentDefault)); 517 518 // Flip the context and draw the image. 519 CGContextSaveGState(context); 520 CGContextTranslateCTM(context, 0.0, height); 521 CGContextScaleCTM(context, 1.0, -1.0); 522 523 CGContextDrawImage(context, CGRectMake(0, 0, width, height), image.get()); 524 525 CGContextRestoreGState(context); 526} 527 528void NetscapePluginInstanceProxy::snapshot(CGContextRef context, unsigned width, unsigned height) 529{ 530 uint32_t requestID = nextRequestID(); 531 _WKPHPluginInstanceSnapshot(m_pluginHostProxy->port(), m_pluginID, requestID, width, height); 532 533 auto reply = waitForReply<NetscapePluginInstanceProxy::BooleanAndDataReply>(requestID); 534 if (!reply || !reply->m_returnValue) 535 return; 536 537 RetainPtr<CGDataProvider> dataProvider = adoptCF(CGDataProviderCreateWithCFData(reply->m_result.get())); 538 RetainPtr<CGColorSpaceRef> colorSpace = adoptCF(CGColorSpaceCreateDeviceRGB()); 539 RetainPtr<CGImageRef> image = adoptCF(CGImageCreate(width, height, 8, 32, width * 4, colorSpace.get(), kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host, dataProvider.get(), 0, false, kCGRenderingIntentDefault)); 540 541 CGContextDrawImage(context, CGRectMake(0, 0, width, height), image.get()); 542} 543 544void NetscapePluginInstanceProxy::stopTimers() 545{ 546 _WKPHPluginInstanceStopTimers(m_pluginHostProxy->port(), m_pluginID); 547} 548 549void NetscapePluginInstanceProxy::status(const char* message) 550{ 551 RetainPtr<CFStringRef> status = adoptCF(CFStringCreateWithCString(0, message ? message : "", kCFStringEncodingUTF8)); 552 if (!status) 553 return; 554 555 WebView *wv = [m_pluginView webView]; 556 [[wv _UIDelegateForwarder] webView:wv setStatusText:(NSString *)status.get()]; 557} 558 559NPError NetscapePluginInstanceProxy::loadURL(const char* url, const char* target, const char* postData, uint32_t postLen, LoadURLFlags flags, uint32_t& streamID) 560{ 561 if (!url) 562 return NPERR_INVALID_PARAM; 563 564 NSMutableURLRequest *request = [m_pluginView requestWithURLCString:url]; 565 566 if (flags & IsPost) { 567 NSData *httpBody = nil; 568 569 if (flags & PostDataIsFile) { 570 // If we're posting a file, buf is either a file URL or a path to the file. 571 if (!postData) 572 return NPERR_INVALID_PARAM; 573 RetainPtr<CFStringRef> bufString = adoptCF(CFStringCreateWithCString(kCFAllocatorDefault, postData, kCFStringEncodingWindowsLatin1)); 574 if (!bufString) 575 return NPERR_INVALID_PARAM; 576 577 NSURL *fileURL = [NSURL _web_URLWithDataAsString:(NSString *)bufString.get()]; 578 NSString *path; 579 if ([fileURL isFileURL]) 580 path = [fileURL path]; 581 else 582 path = (NSString *)bufString.get(); 583 httpBody = [NSData dataWithContentsOfFile:[path _webkit_fixedCarbonPOSIXPath]]; 584 if (!httpBody) 585 return NPERR_FILE_NOT_FOUND; 586 } else 587 httpBody = [NSData dataWithBytes:postData length:postLen]; 588 589 if (![httpBody length]) 590 return NPERR_INVALID_PARAM; 591 592 [request setHTTPMethod:@"POST"]; 593 594 if (flags & AllowHeadersInPostData) { 595 if ([httpBody _web_startsWithBlankLine]) 596 httpBody = [httpBody subdataWithRange:NSMakeRange(1, [httpBody length] - 1)]; 597 else { 598 NSInteger location = [httpBody _web_locationAfterFirstBlankLine]; 599 if (location != NSNotFound) { 600 // If the blank line is somewhere in the middle of postData, everything before is the header. 601 NSData *headerData = [httpBody subdataWithRange:NSMakeRange(0, location)]; 602 NSMutableDictionary *header = [headerData _webkit_parseRFC822HeaderFields]; 603 unsigned dataLength = [httpBody length] - location; 604 605 // Sometimes plugins like to set Content-Length themselves when they post, 606 // but CFNetwork does not like that. So we will remove the header 607 // and instead truncate the data to the requested length. 608 NSString *contentLength = [header objectForKey:@"Content-Length"]; 609 610 if (contentLength) 611 dataLength = std::min(static_cast<unsigned>([contentLength intValue]), dataLength); 612 [header removeObjectForKey:@"Content-Length"]; 613 614 if ([header count] > 0) 615 [request setAllHTTPHeaderFields:header]; 616 617 // Everything after the blank line is the actual content of the POST. 618 httpBody = [httpBody subdataWithRange:NSMakeRange(location, dataLength)]; 619 } 620 } 621 } 622 623 if (![httpBody length]) 624 return NPERR_INVALID_PARAM; 625 626 // Plug-ins expect to receive uncached data when doing a POST (3347134). 627 [request setCachePolicy:NSURLRequestReloadIgnoringCacheData]; 628 [request setHTTPBody:httpBody]; 629 } 630 631 return loadRequest(request, target, flags & AllowPopups, streamID); 632} 633 634void NetscapePluginInstanceProxy::performRequest(PluginRequest* pluginRequest) 635{ 636 // Loading the request can cause the instance proxy to go away, so protect it. 637 Ref<NetscapePluginInstanceProxy> protect(*this); 638 639 ASSERT(m_pluginView); 640 641 NSURLRequest *request = pluginRequest->request(); 642 NSString *frameName = pluginRequest->frameName(); 643 WebFrame *frame = nil; 644 645 NSURL *URL = [request URL]; 646 NSString *JSString = [URL _webkit_scriptIfJavaScriptURL]; 647 648 ASSERT(frameName || JSString); 649 if (frameName) { 650 // FIXME - need to get rid of this window creation which 651 // bypasses normal targeted link handling 652 frame = kit(core([m_pluginView webFrame])->loader().findFrameForNavigation(frameName)); 653 if (!frame) { 654 WebView *currentWebView = [m_pluginView webView]; 655 NSDictionary *features = [[NSDictionary alloc] init]; 656 WebView *newWebView = [[currentWebView _UIDelegateForwarder] webView:currentWebView 657 createWebViewWithRequest:nil 658 windowFeatures:features]; 659 [features release]; 660 661 if (!newWebView) { 662 _WKPHLoadURLNotify(m_pluginHostProxy->port(), m_pluginID, pluginRequest->requestID(), NPERR_GENERIC_ERROR); 663 return; 664 } 665 666 frame = [newWebView mainFrame]; 667 core(frame)->tree().setName(frameName); 668 [[newWebView _UIDelegateForwarder] webViewShow:newWebView]; 669 } 670 } 671 672 if (JSString) { 673 ASSERT(!frame || [m_pluginView webFrame] == frame); 674 evaluateJavaScript(pluginRequest); 675 } else { 676 [frame loadRequest:request]; 677 678 // Check if another plug-in view or even this view is waiting for the frame to load. 679 // If it is, tell it that the load was cancelled because it will be anyway. 680 WebHostedNetscapePluginView *view = [frame _internalLoadDelegate]; 681 if (view != nil) { 682 ASSERT([view isKindOfClass:[WebHostedNetscapePluginView class]]); 683 [view webFrame:frame didFinishLoadWithReason:NPRES_USER_BREAK]; 684 } 685 m_pendingFrameLoads.set(frame, pluginRequest); 686 [frame _setInternalLoadDelegate:m_pluginView]; 687 } 688 689} 690 691void NetscapePluginInstanceProxy::webFrameDidFinishLoadWithReason(WebFrame* webFrame, NPReason reason) 692{ 693 FrameLoadMap::iterator it = m_pendingFrameLoads.find(webFrame); 694 ASSERT(it != m_pendingFrameLoads.end()); 695 696 PluginRequest* pluginRequest = it->value.get(); 697 _WKPHLoadURLNotify(m_pluginHostProxy->port(), m_pluginID, pluginRequest->requestID(), reason); 698 699 m_pendingFrameLoads.remove(it); 700 701 [webFrame _setInternalLoadDelegate:nil]; 702} 703 704void NetscapePluginInstanceProxy::evaluateJavaScript(PluginRequest* pluginRequest) 705{ 706 NSURL *URL = [pluginRequest->request() URL]; 707 NSString *JSString = [URL _webkit_scriptIfJavaScriptURL]; 708 ASSERT(JSString); 709 710 Ref<NetscapePluginInstanceProxy> protect(*this); // Executing arbitrary JavaScript can destroy the proxy. 711 712 NSString *result = [[m_pluginView webFrame] _stringByEvaluatingJavaScriptFromString:JSString forceUserGesture:pluginRequest->allowPopups()]; 713 714 // Don't continue if stringByEvaluatingJavaScriptFromString caused the plug-in to stop. 715 if (!m_pluginHostProxy) 716 return; 717 718 if (pluginRequest->frameName() != nil) 719 return; 720 721 if ([result length] > 0) { 722 // Don't call NPP_NewStream and other stream methods if there is no JS result to deliver. This is what Mozilla does. 723 NSData *JSData = [result dataUsingEncoding:NSUTF8StringEncoding]; 724 725 RefPtr<HostedNetscapePluginStream> stream = HostedNetscapePluginStream::create(this, pluginRequest->requestID(), pluginRequest->request()); 726 m_streams.add(stream->streamID(), stream); 727 728 RetainPtr<NSURLResponse> response = adoptNS([[NSURLResponse alloc] initWithURL:URL 729 MIMEType:@"text/plain" 730 expectedContentLength:[JSData length] 731 textEncodingName:nil]); 732 stream->startStreamWithResponse(response.get()); 733 stream->didReceiveData(0, static_cast<const char*>([JSData bytes]), [JSData length]); 734 stream->didFinishLoading(0); 735 } 736} 737 738void NetscapePluginInstanceProxy::requestTimerFired(Timer<NetscapePluginInstanceProxy>*) 739{ 740 ASSERT(!m_pluginRequests.isEmpty()); 741 ASSERT(m_pluginView); 742 743 RefPtr<PluginRequest> request = m_pluginRequests.first(); 744 m_pluginRequests.removeFirst(); 745 746 if (!m_pluginRequests.isEmpty()) 747 m_requestTimer.startOneShot(0); 748 749 performRequest(request.get()); 750} 751 752NPError NetscapePluginInstanceProxy::loadRequest(NSURLRequest *request, const char* cTarget, bool allowPopups, uint32_t& requestID) 753{ 754 NSURL *URL = [request URL]; 755 756 if (!URL) 757 return NPERR_INVALID_URL; 758 759 // Don't allow requests to be loaded when the document loader is stopping all loaders. 760 DocumentLoader* documentLoader = [[m_pluginView dataSource] _documentLoader]; 761 if (!documentLoader || documentLoader->isStopping()) 762 return NPERR_GENERIC_ERROR; 763 764 NSString *target = nil; 765 if (cTarget) { 766 // Find the frame given the target string. 767 target = [NSString stringWithCString:cTarget encoding:NSISOLatin1StringEncoding]; 768 } 769 WebFrame *frame = [m_pluginView webFrame]; 770 771 // don't let a plugin start any loads if it is no longer part of a document that is being 772 // displayed unless the loads are in the same frame as the plugin. 773 if (documentLoader != core([m_pluginView webFrame])->loader().activeDocumentLoader() && 774 (!cTarget || [frame findFrameNamed:target] != frame)) { 775 return NPERR_GENERIC_ERROR; 776 } 777 778 NSString *JSString = [URL _webkit_scriptIfJavaScriptURL]; 779 if (JSString != nil) { 780 if (![[[m_pluginView webView] preferences] isJavaScriptEnabled]) { 781 // Return NPERR_GENERIC_ERROR if JS is disabled. This is what Mozilla does. 782 return NPERR_GENERIC_ERROR; 783 } 784 } else { 785 if (!core([m_pluginView webFrame])->document()->securityOrigin()->canDisplay(URL)) 786 return NPERR_GENERIC_ERROR; 787 } 788 789 // FIXME: Handle wraparound 790 requestID = ++m_currentURLRequestID; 791 792 if (cTarget || JSString) { 793 // Make when targetting a frame or evaluating a JS string, perform the request after a delay because we don't 794 // want to potentially kill the plug-in inside of its URL request. 795 796 if (JSString && target && [frame findFrameNamed:target] != frame) { 797 // For security reasons, only allow JS requests to be made on the frame that contains the plug-in. 798 return NPERR_INVALID_PARAM; 799 } 800 801 RefPtr<PluginRequest> pluginRequest = PluginRequest::create(requestID, request, target, allowPopups); 802 m_pluginRequests.append(pluginRequest.release()); 803 m_requestTimer.startOneShot(0); 804 } else { 805 RefPtr<HostedNetscapePluginStream> stream = HostedNetscapePluginStream::create(this, requestID, request); 806 807 ASSERT(!m_streams.contains(requestID)); 808 m_streams.add(requestID, stream); 809 stream->start(); 810 } 811 812 return NPERR_NO_ERROR; 813} 814 815std::unique_ptr<NetscapePluginInstanceProxy::Reply> NetscapePluginInstanceProxy::processRequestsAndWaitForReply(uint32_t requestID) 816{ 817 ASSERT(m_pluginHostProxy); 818 819 std::unique_ptr<Reply> reply; 820 821 while (!(reply = m_replies.take(requestID))) { 822 if (!m_pluginHostProxy->processRequests()) 823 return nullptr; 824 825 // The host proxy can be destroyed while executing a nested processRequests() call, in which case it's normal 826 // to get a success result, but be unable to keep looping. 827 if (!m_pluginHostProxy) 828 return nullptr; 829 } 830 831 return reply; 832} 833 834// NPRuntime support 835bool NetscapePluginInstanceProxy::getWindowNPObject(uint32_t& objectID) 836{ 837 Frame* frame = core([m_pluginView webFrame]); 838 if (!frame) 839 return false; 840 841 if (!frame->script().canExecuteScripts(NotAboutToExecuteScript)) 842 objectID = 0; 843 else 844 objectID = m_localObjects.idForObject(pluginWorld().vm(), frame->script().windowShell(pluginWorld())->window()); 845 846 return true; 847} 848 849bool NetscapePluginInstanceProxy::getPluginElementNPObject(uint32_t& objectID) 850{ 851 Frame* frame = core([m_pluginView webFrame]); 852 if (!frame) 853 return false; 854 855 if (JSObject* object = frame->script().jsObjectForPluginElement([m_pluginView element])) 856 objectID = m_localObjects.idForObject(pluginWorld().vm(), object); 857 else 858 objectID = 0; 859 860 return true; 861} 862 863bool NetscapePluginInstanceProxy::forgetBrowserObjectID(uint32_t objectID) 864{ 865 return m_localObjects.forget(objectID); 866} 867 868bool NetscapePluginInstanceProxy::evaluate(uint32_t objectID, const String& script, data_t& resultData, mach_msg_type_number_t& resultLength, bool allowPopups) 869{ 870 resultData = nullptr; 871 resultLength = 0; 872 873 if (m_inDestroy) 874 return false; 875 876 if (!m_localObjects.contains(objectID)) { 877 LOG_ERROR("NetscapePluginInstanceProxy::evaluate: local object %u doesn't exist.", objectID); 878 return false; 879 } 880 881 Frame* frame = core([m_pluginView webFrame]); 882 if (!frame) 883 return false; 884 885 JSLockHolder lock(pluginWorld().vm()); 886 Strong<JSGlobalObject> globalObject(pluginWorld().vm(), frame->script().globalObject(pluginWorld())); 887 ExecState* exec = globalObject->globalExec(); 888 889 UserGestureIndicator gestureIndicator(allowPopups ? DefinitelyProcessingUserGesture : PossiblyProcessingUserGesture); 890 891 JSValue result = JSC::evaluate(exec, makeSource(script)); 892 893 marshalValue(exec, result, resultData, resultLength); 894 exec->clearException(); 895 return true; 896} 897 898bool NetscapePluginInstanceProxy::invoke(uint32_t objectID, const Identifier& methodName, data_t argumentsData, mach_msg_type_number_t argumentsLength, data_t& resultData, mach_msg_type_number_t& resultLength) 899{ 900 resultData = nullptr; 901 resultLength = 0; 902 903 if (m_inDestroy) 904 return false; 905 906 JSObject* object = m_localObjects.get(objectID); 907 if (!object) { 908 LOG_ERROR("NetscapePluginInstanceProxy::invoke: local object %u doesn't exist.", objectID); 909 return false; 910 } 911 912 Frame* frame = core([m_pluginView webFrame]); 913 if (!frame) 914 return false; 915 916 ExecState* exec = frame->script().globalObject(pluginWorld())->globalExec(); 917 JSLockHolder lock(exec); 918 JSValue function = object->get(exec, methodName); 919 CallData callData; 920 CallType callType = getCallData(function, callData); 921 if (callType == CallTypeNone) 922 return false; 923 924 MarkedArgumentBuffer argList; 925 demarshalValues(exec, argumentsData, argumentsLength, argList); 926 927 JSValue value = call(exec, function, callType, callData, object, argList); 928 929 marshalValue(exec, value, resultData, resultLength); 930 exec->clearException(); 931 return true; 932} 933 934bool NetscapePluginInstanceProxy::invokeDefault(uint32_t objectID, data_t argumentsData, mach_msg_type_number_t argumentsLength, data_t& resultData, mach_msg_type_number_t& resultLength) 935{ 936 if (m_inDestroy) 937 return false; 938 939 JSObject* object = m_localObjects.get(objectID); 940 if (!object) { 941 LOG_ERROR("NetscapePluginInstanceProxy::invokeDefault: local object %u doesn't exist.", objectID); 942 return false; 943 } 944 945 Frame* frame = core([m_pluginView webFrame]); 946 if (!frame) 947 return false; 948 949 ExecState* exec = frame->script().globalObject(pluginWorld())->globalExec(); 950 JSLockHolder lock(exec); 951 CallData callData; 952 CallType callType = object->methodTable()->getCallData(object, callData); 953 if (callType == CallTypeNone) 954 return false; 955 956 MarkedArgumentBuffer argList; 957 demarshalValues(exec, argumentsData, argumentsLength, argList); 958 959 JSValue value = call(exec, object, callType, callData, object, argList); 960 961 marshalValue(exec, value, resultData, resultLength); 962 exec->clearException(); 963 return true; 964} 965 966bool NetscapePluginInstanceProxy::construct(uint32_t objectID, data_t argumentsData, mach_msg_type_number_t argumentsLength, data_t& resultData, mach_msg_type_number_t& resultLength) 967{ 968 if (m_inDestroy) 969 return false; 970 971 JSObject* object = m_localObjects.get(objectID); 972 if (!object) { 973 LOG_ERROR("NetscapePluginInstanceProxy::construct: local object %u doesn't exist.", objectID); 974 return false; 975 } 976 977 Frame* frame = core([m_pluginView webFrame]); 978 if (!frame) 979 return false; 980 981 ExecState* exec = frame->script().globalObject(pluginWorld())->globalExec(); 982 JSLockHolder lock(exec); 983 984 ConstructData constructData; 985 ConstructType constructType = object->methodTable()->getConstructData(object, constructData); 986 if (constructType == ConstructTypeNone) 987 return false; 988 989 MarkedArgumentBuffer argList; 990 demarshalValues(exec, argumentsData, argumentsLength, argList); 991 992 JSValue value = JSC::construct(exec, object, constructType, constructData, argList); 993 994 marshalValue(exec, value, resultData, resultLength); 995 exec->clearException(); 996 return true; 997} 998 999bool NetscapePluginInstanceProxy::getProperty(uint32_t objectID, const Identifier& propertyName, data_t& resultData, mach_msg_type_number_t& resultLength) 1000{ 1001 if (m_inDestroy) 1002 return false; 1003 1004 JSObject* object = m_localObjects.get(objectID); 1005 if (!object) { 1006 LOG_ERROR("NetscapePluginInstanceProxy::getProperty: local object %u doesn't exist.", objectID); 1007 return false; 1008 } 1009 1010 Frame* frame = core([m_pluginView webFrame]); 1011 if (!frame) 1012 return false; 1013 1014 ExecState* exec = frame->script().globalObject(pluginWorld())->globalExec(); 1015 JSLockHolder lock(exec); 1016 JSValue value = object->get(exec, propertyName); 1017 1018 marshalValue(exec, value, resultData, resultLength); 1019 exec->clearException(); 1020 return true; 1021} 1022 1023bool NetscapePluginInstanceProxy::getProperty(uint32_t objectID, unsigned propertyName, data_t& resultData, mach_msg_type_number_t& resultLength) 1024{ 1025 JSObject* object = m_localObjects.get(objectID); 1026 if (!object) { 1027 LOG_ERROR("NetscapePluginInstanceProxy::getProperty: local object %u doesn't exist.", objectID); 1028 return false; 1029 } 1030 1031 Frame* frame = core([m_pluginView webFrame]); 1032 if (!frame) 1033 return false; 1034 1035 ExecState* exec = frame->script().globalObject(pluginWorld())->globalExec(); 1036 JSLockHolder lock(exec); 1037 JSValue value = object->get(exec, propertyName); 1038 1039 marshalValue(exec, value, resultData, resultLength); 1040 exec->clearException(); 1041 return true; 1042} 1043 1044bool NetscapePluginInstanceProxy::setProperty(uint32_t objectID, const Identifier& propertyName, data_t valueData, mach_msg_type_number_t valueLength) 1045{ 1046 if (m_inDestroy) 1047 return false; 1048 1049 JSObject* object = m_localObjects.get(objectID); 1050 if (!object) { 1051 LOG_ERROR("NetscapePluginInstanceProxy::setProperty: local object %u doesn't exist.", objectID); 1052 return false; 1053 } 1054 1055 Frame* frame = core([m_pluginView webFrame]); 1056 if (!frame) 1057 return false; 1058 1059 ExecState* exec = frame->script().globalObject(pluginWorld())->globalExec(); 1060 JSLockHolder lock(exec); 1061 1062 JSValue value = demarshalValue(exec, valueData, valueLength); 1063 PutPropertySlot slot(object); 1064 object->methodTable()->put(object, exec, propertyName, value, slot); 1065 1066 exec->clearException(); 1067 return true; 1068} 1069 1070bool NetscapePluginInstanceProxy::setProperty(uint32_t objectID, unsigned propertyName, data_t valueData, mach_msg_type_number_t valueLength) 1071{ 1072 if (m_inDestroy) 1073 return false; 1074 1075 JSObject* object = m_localObjects.get(objectID); 1076 if (!object) { 1077 LOG_ERROR("NetscapePluginInstanceProxy::setProperty: local object %u doesn't exist.", objectID); 1078 return false; 1079 } 1080 1081 Frame* frame = core([m_pluginView webFrame]); 1082 if (!frame) 1083 return false; 1084 1085 ExecState* exec = frame->script().globalObject(pluginWorld())->globalExec(); 1086 JSLockHolder lock(exec); 1087 1088 JSValue value = demarshalValue(exec, valueData, valueLength); 1089 object->methodTable()->putByIndex(object, exec, propertyName, value, false); 1090 1091 exec->clearException(); 1092 return true; 1093} 1094 1095bool NetscapePluginInstanceProxy::removeProperty(uint32_t objectID, const Identifier& propertyName) 1096{ 1097 if (m_inDestroy) 1098 return false; 1099 1100 JSObject* object = m_localObjects.get(objectID); 1101 if (!object) { 1102 LOG_ERROR("NetscapePluginInstanceProxy::removeProperty: local object %u doesn't exist.", objectID); 1103 return false; 1104 } 1105 1106 Frame* frame = core([m_pluginView webFrame]); 1107 if (!frame) 1108 return false; 1109 1110 ExecState* exec = frame->script().globalObject(pluginWorld())->globalExec(); 1111 JSLockHolder lock(exec); 1112 if (!object->hasProperty(exec, propertyName)) { 1113 exec->clearException(); 1114 return false; 1115 } 1116 1117 object->methodTable()->deleteProperty(object, exec, propertyName); 1118 exec->clearException(); 1119 return true; 1120} 1121 1122bool NetscapePluginInstanceProxy::removeProperty(uint32_t objectID, unsigned propertyName) 1123{ 1124 if (m_inDestroy) 1125 return false; 1126 1127 JSObject* object = m_localObjects.get(objectID); 1128 if (!object) { 1129 LOG_ERROR("NetscapePluginInstanceProxy::removeProperty: local object %u doesn't exist.", objectID); 1130 return false; 1131 } 1132 1133 Frame* frame = core([m_pluginView webFrame]); 1134 if (!frame) 1135 return false; 1136 1137 ExecState* exec = frame->script().globalObject(pluginWorld())->globalExec(); 1138 JSLockHolder lock(exec); 1139 if (!object->hasProperty(exec, propertyName)) { 1140 exec->clearException(); 1141 return false; 1142 } 1143 1144 object->methodTable()->deletePropertyByIndex(object, exec, propertyName); 1145 exec->clearException(); 1146 return true; 1147} 1148 1149bool NetscapePluginInstanceProxy::hasProperty(uint32_t objectID, const Identifier& propertyName) 1150{ 1151 if (m_inDestroy) 1152 return false; 1153 1154 JSObject* object = m_localObjects.get(objectID); 1155 if (!object) { 1156 LOG_ERROR("NetscapePluginInstanceProxy::hasProperty: local object %u doesn't exist.", objectID); 1157 return false; 1158 } 1159 1160 Frame* frame = core([m_pluginView webFrame]); 1161 if (!frame) 1162 return false; 1163 1164 ExecState* exec = frame->script().globalObject(pluginWorld())->globalExec(); 1165 bool result = object->hasProperty(exec, propertyName); 1166 exec->clearException(); 1167 1168 return result; 1169} 1170 1171bool NetscapePluginInstanceProxy::hasProperty(uint32_t objectID, unsigned propertyName) 1172{ 1173 if (m_inDestroy) 1174 return false; 1175 1176 JSObject* object = m_localObjects.get(objectID); 1177 if (!object) { 1178 LOG_ERROR("NetscapePluginInstanceProxy::hasProperty: local object %u doesn't exist.", objectID); 1179 return false; 1180 } 1181 1182 Frame* frame = core([m_pluginView webFrame]); 1183 if (!frame) 1184 return false; 1185 1186 ExecState* exec = frame->script().globalObject(pluginWorld())->globalExec(); 1187 bool result = object->hasProperty(exec, propertyName); 1188 exec->clearException(); 1189 1190 return result; 1191} 1192 1193bool NetscapePluginInstanceProxy::hasMethod(uint32_t objectID, const Identifier& methodName) 1194{ 1195 if (m_inDestroy) 1196 return false; 1197 1198 JSObject* object = m_localObjects.get(objectID); 1199 if (!object) { 1200 LOG_ERROR("NetscapePluginInstanceProxy::hasMethod: local object %u doesn't exist.", objectID); 1201 return false; 1202 } 1203 1204 Frame* frame = core([m_pluginView webFrame]); 1205 if (!frame) 1206 return false; 1207 1208 ExecState* exec = frame->script().globalObject(pluginWorld())->globalExec(); 1209 JSLockHolder lock(exec); 1210 JSValue func = object->get(exec, methodName); 1211 exec->clearException(); 1212 return !func.isUndefined(); 1213} 1214 1215bool NetscapePluginInstanceProxy::enumerate(uint32_t objectID, data_t& resultData, mach_msg_type_number_t& resultLength) 1216{ 1217 if (m_inDestroy) 1218 return false; 1219 1220 JSObject* object = m_localObjects.get(objectID); 1221 if (!object) { 1222 LOG_ERROR("NetscapePluginInstanceProxy::enumerate: local object %u doesn't exist.", objectID); 1223 return false; 1224 } 1225 1226 Frame* frame = core([m_pluginView webFrame]); 1227 if (!frame) 1228 return false; 1229 1230 ExecState* exec = frame->script().globalObject(pluginWorld())->globalExec(); 1231 JSLockHolder lock(exec); 1232 1233 PropertyNameArray propertyNames(exec); 1234 object->methodTable()->getPropertyNames(object, exec, propertyNames, ExcludeDontEnumProperties); 1235 1236 RetainPtr<NSMutableArray*> array = adoptNS([[NSMutableArray alloc] init]); 1237 for (unsigned i = 0; i < propertyNames.size(); i++) { 1238 uint64_t methodName = reinterpret_cast<uint64_t>(_NPN_GetStringIdentifier(propertyNames[i].string().utf8().data())); 1239 1240 [array.get() addObject:[NSNumber numberWithLongLong:methodName]]; 1241 } 1242 1243 NSData *data = [NSPropertyListSerialization dataWithPropertyList:array.get() format:NSPropertyListBinaryFormat_v1_0 options:0 error:nullptr]; 1244 ASSERT(data); 1245 1246 resultLength = [data length]; 1247 mig_allocate(reinterpret_cast<vm_address_t*>(&resultData), resultLength); 1248 1249 memcpy(resultData, [data bytes], resultLength); 1250 1251 exec->clearException(); 1252 1253 return true; 1254} 1255 1256static bool getObjectID(NetscapePluginInstanceProxy* pluginInstanceProxy, JSObject* object, uint64_t& objectID) 1257{ 1258 if (object->classInfo() != ProxyRuntimeObject::info()) 1259 return false; 1260 1261 ProxyRuntimeObject* runtimeObject = static_cast<ProxyRuntimeObject*>(object); 1262 ProxyInstance* instance = runtimeObject->getInternalProxyInstance(); 1263 if (!instance) 1264 return false; 1265 1266 if (instance->instanceProxy() != pluginInstanceProxy) 1267 return false; 1268 1269 objectID = instance->objectID(); 1270 return true; 1271} 1272 1273void NetscapePluginInstanceProxy::addValueToArray(NSMutableArray *array, ExecState* exec, JSValue value) 1274{ 1275 JSLockHolder lock(exec); 1276 1277 if (value.isString()) { 1278 [array addObject:[NSNumber numberWithInt:StringValueType]]; 1279 [array addObject:value.toWTFString(exec)]; 1280 } else if (value.isNumber()) { 1281 [array addObject:[NSNumber numberWithInt:DoubleValueType]]; 1282 [array addObject:[NSNumber numberWithDouble:value.toNumber(exec)]]; 1283 } else if (value.isBoolean()) { 1284 [array addObject:[NSNumber numberWithInt:BoolValueType]]; 1285 [array addObject:[NSNumber numberWithBool:value.toBoolean(exec)]]; 1286 } else if (value.isNull()) 1287 [array addObject:[NSNumber numberWithInt:NullValueType]]; 1288 else if (value.isObject()) { 1289 JSObject* object = asObject(value); 1290 uint64_t objectID; 1291 if (getObjectID(this, object, objectID)) { 1292 [array addObject:[NSNumber numberWithInt:NPObjectValueType]]; 1293 [array addObject:[NSNumber numberWithInt:objectID]]; 1294 } else { 1295 [array addObject:[NSNumber numberWithInt:JSObjectValueType]]; 1296 [array addObject:[NSNumber numberWithInt:m_localObjects.idForObject(exec->vm(), object)]]; 1297 } 1298 } else 1299 [array addObject:[NSNumber numberWithInt:VoidValueType]]; 1300} 1301 1302void NetscapePluginInstanceProxy::marshalValue(ExecState* exec, JSValue value, data_t& resultData, mach_msg_type_number_t& resultLength) 1303{ 1304 RetainPtr<NSMutableArray*> array = adoptNS([[NSMutableArray alloc] init]); 1305 1306 addValueToArray(array.get(), exec, value); 1307 1308 NSData *data = [NSPropertyListSerialization dataWithPropertyList:array.get() format:NSPropertyListBinaryFormat_v1_0 options:0 error:nullptr]; 1309 ASSERT(data); 1310 1311 resultLength = data.length; 1312 mig_allocate(reinterpret_cast<vm_address_t*>(&resultData), resultLength); 1313 1314 memcpy(resultData, data.bytes, resultLength); 1315} 1316 1317RetainPtr<NSData *> NetscapePluginInstanceProxy::marshalValues(ExecState* exec, const ArgList& args) 1318{ 1319 RetainPtr<NSMutableArray*> array = adoptNS([[NSMutableArray alloc] init]); 1320 1321 for (unsigned i = 0; i < args.size(); i++) 1322 addValueToArray(array.get(), exec, args.at(i)); 1323 1324 NSData *data = [NSPropertyListSerialization dataWithPropertyList:array.get() format:NSPropertyListBinaryFormat_v1_0 options:0 error:nullptr]; 1325 ASSERT(data); 1326 1327 return data; 1328} 1329 1330bool NetscapePluginInstanceProxy::demarshalValueFromArray(ExecState* exec, NSArray *array, NSUInteger& index, JSValue& result) 1331{ 1332 if (index == [array count]) 1333 return false; 1334 1335 int type = [[array objectAtIndex:index++] intValue]; 1336 switch (type) { 1337 case VoidValueType: 1338 result = jsUndefined(); 1339 return true; 1340 case NullValueType: 1341 result = jsNull(); 1342 return true; 1343 case BoolValueType: 1344 result = jsBoolean([[array objectAtIndex:index++] boolValue]); 1345 return true; 1346 case DoubleValueType: 1347 result = jsNumber([[array objectAtIndex:index++] doubleValue]); 1348 return true; 1349 case StringValueType: { 1350 NSString *string = [array objectAtIndex:index++]; 1351 1352 result = jsString(exec, String(string)); 1353 return true; 1354 } 1355 case JSObjectValueType: { 1356 uint32_t objectID = [[array objectAtIndex:index++] intValue]; 1357 1358 result = m_localObjects.get(objectID); 1359 ASSERT(result); 1360 return true; 1361 } 1362 case NPObjectValueType: { 1363 uint32_t objectID = [[array objectAtIndex:index++] intValue]; 1364 1365 Frame* frame = core([m_pluginView webFrame]); 1366 if (!frame) 1367 return false; 1368 1369 if (!frame->script().canExecuteScripts(NotAboutToExecuteScript)) 1370 return false; 1371 1372 RefPtr<RootObject> rootObject = frame->script().createRootObject(m_pluginView); 1373 if (!rootObject) 1374 return false; 1375 1376 result = ProxyInstance::create(rootObject.release(), this, objectID)->createRuntimeObject(exec); 1377 return true; 1378 } 1379 default: 1380 ASSERT_NOT_REACHED(); 1381 return false; 1382 } 1383} 1384 1385JSValue NetscapePluginInstanceProxy::demarshalValue(ExecState* exec, const char* valueData, mach_msg_type_number_t valueLength) 1386{ 1387 RetainPtr<NSData*> data = adoptNS([[NSData alloc] initWithBytesNoCopy:(void*)valueData length:valueLength freeWhenDone:NO]); 1388 1389 NSArray *array = [NSPropertyListSerialization propertyListWithData:data.get() options:NSPropertyListImmutable format:nullptr error:nullptr]; 1390 1391 NSUInteger position = 0; 1392 JSValue value; 1393 bool result = demarshalValueFromArray(exec, array, position, value); 1394 ASSERT_UNUSED(result, result); 1395 1396 return value; 1397} 1398 1399void NetscapePluginInstanceProxy::demarshalValues(ExecState* exec, data_t valuesData, mach_msg_type_number_t valuesLength, MarkedArgumentBuffer& result) 1400{ 1401 RetainPtr<NSData*> data = adoptNS([[NSData alloc] initWithBytesNoCopy:valuesData length:valuesLength freeWhenDone:NO]); 1402 1403 NSArray *array = [NSPropertyListSerialization propertyListWithData:data.get() options:NSPropertyListImmutable format:nullptr error:nullptr]; 1404 1405 NSUInteger position = 0; 1406 JSValue value; 1407 while (demarshalValueFromArray(exec, array, position, value)) 1408 result.append(value); 1409} 1410 1411void NetscapePluginInstanceProxy::retainLocalObject(JSC::JSValue value) 1412{ 1413 if (!value.isObject() || value.inherits(ProxyRuntimeObject::info())) 1414 return; 1415 1416 m_localObjects.retain(asObject(value)); 1417} 1418 1419void NetscapePluginInstanceProxy::releaseLocalObject(JSC::JSValue value) 1420{ 1421 if (!value.isObject() || value.inherits(ProxyRuntimeObject::info())) 1422 return; 1423 1424 m_localObjects.release(asObject(value)); 1425} 1426 1427PassRefPtr<Instance> NetscapePluginInstanceProxy::createBindingsInstance(PassRefPtr<RootObject> rootObject) 1428{ 1429 uint32_t requestID = nextRequestID(); 1430 1431 if (_WKPHGetScriptableNPObject(m_pluginHostProxy->port(), m_pluginID, requestID) != KERN_SUCCESS) 1432 return nullptr; 1433 1434 auto reply = waitForReply<GetScriptableNPObjectReply>(requestID); 1435 if (!reply) 1436 return nullptr; 1437 1438 if (!reply->m_objectID) 1439 return nullptr; 1440 1441 // Since the reply was non-null, "this" is still a valid pointer. 1442 return ProxyInstance::create(rootObject, this, reply->m_objectID); 1443} 1444 1445void NetscapePluginInstanceProxy::addInstance(ProxyInstance* instance) 1446{ 1447 ASSERT(!m_instances.contains(instance)); 1448 1449 m_instances.add(instance); 1450} 1451 1452void NetscapePluginInstanceProxy::removeInstance(ProxyInstance* instance) 1453{ 1454 ASSERT(m_instances.contains(instance)); 1455 1456 m_instances.remove(instance); 1457} 1458 1459void NetscapePluginInstanceProxy::willCallPluginFunction() 1460{ 1461 m_pluginFunctionCallDepth++; 1462} 1463 1464void NetscapePluginInstanceProxy::didCallPluginFunction(bool& stopped) 1465{ 1466 ASSERT(m_pluginFunctionCallDepth > 0); 1467 m_pluginFunctionCallDepth--; 1468 1469 // If -stop was called while we were calling into a plug-in function, and we're no longer 1470 // inside a plug-in function, stop now. 1471 if (!m_pluginFunctionCallDepth && m_shouldStopSoon) { 1472 m_shouldStopSoon = false; 1473 [m_pluginView stop]; 1474 stopped = true; 1475 } 1476} 1477 1478bool NetscapePluginInstanceProxy::shouldStop() 1479{ 1480 if (m_pluginFunctionCallDepth) { 1481 m_shouldStopSoon = true; 1482 return false; 1483 } 1484 1485 return true; 1486} 1487 1488uint32_t NetscapePluginInstanceProxy::nextRequestID() 1489{ 1490 uint32_t requestID = ++m_currentRequestID; 1491 1492 // We don't want to return the HashMap empty/deleted "special keys" 1493 if (requestID == 0 || requestID == static_cast<uint32_t>(-1)) 1494 return nextRequestID(); 1495 1496 return requestID; 1497} 1498 1499void NetscapePluginInstanceProxy::invalidateRect(double x, double y, double width, double height) 1500{ 1501 ASSERT(m_pluginView); 1502 1503 m_pluginIsWaitingForDraw = true; 1504 [m_pluginView invalidatePluginContentRect:NSMakeRect(x, y, width, height)]; 1505} 1506 1507void NetscapePluginInstanceProxy::didDraw() 1508{ 1509 if (!m_pluginIsWaitingForDraw) 1510 return; 1511 1512 m_pluginIsWaitingForDraw = false; 1513 _WKPHPluginInstanceDidDraw(m_pluginHostProxy->port(), m_pluginID); 1514} 1515 1516bool NetscapePluginInstanceProxy::getCookies(data_t urlData, mach_msg_type_number_t urlLength, data_t& cookiesData, mach_msg_type_number_t& cookiesLength) 1517{ 1518 ASSERT(m_pluginView); 1519 1520 NSURL *url = [m_pluginView URLWithCString:urlData]; 1521 if (!url) 1522 return false; 1523 1524 if (Frame* frame = core([m_pluginView webFrame])) { 1525 String cookieString = cookies(frame->document(), url); 1526 WTF::CString cookieStringUTF8 = cookieString.utf8(); 1527 if (cookieStringUTF8.isNull()) 1528 return false; 1529 1530 cookiesLength = cookieStringUTF8.length(); 1531 mig_allocate(reinterpret_cast<vm_address_t*>(&cookiesData), cookiesLength); 1532 memcpy(cookiesData, cookieStringUTF8.data(), cookiesLength); 1533 1534 return true; 1535 } 1536 1537 return false; 1538} 1539 1540bool NetscapePluginInstanceProxy::setCookies(data_t urlData, mach_msg_type_number_t urlLength, data_t cookiesData, mach_msg_type_number_t cookiesLength) 1541{ 1542 ASSERT(m_pluginView); 1543 1544 NSURL *url = [m_pluginView URLWithCString:urlData]; 1545 if (!url) 1546 return false; 1547 1548 if (Frame* frame = core([m_pluginView webFrame])) { 1549 String cookieString = String::fromUTF8(cookiesData, cookiesLength); 1550 if (!cookieString) 1551 return false; 1552 1553 WebCore::setCookies(frame->document(), url, cookieString); 1554 return true; 1555 } 1556 1557 return false; 1558} 1559 1560bool NetscapePluginInstanceProxy::getProxy(data_t urlData, mach_msg_type_number_t urlLength, data_t& proxyData, mach_msg_type_number_t& proxyLength) 1561{ 1562 ASSERT(m_pluginView); 1563 1564 NSURL *url = [m_pluginView URLWithCString:urlData]; 1565 if (!url) 1566 return false; 1567 1568 Vector<ProxyServer> proxyServers = proxyServersForURL(url, 0); 1569 WTF::CString proxyStringUTF8 = toString(proxyServers).utf8(); 1570 1571 proxyLength = proxyStringUTF8.length(); 1572 mig_allocate(reinterpret_cast<vm_address_t*>(&proxyData), proxyLength); 1573 memcpy(proxyData, proxyStringUTF8.data(), proxyLength); 1574 1575 return true; 1576} 1577 1578bool NetscapePluginInstanceProxy::getAuthenticationInfo(data_t protocolData, data_t hostData, uint32_t port, data_t schemeData, data_t realmData, 1579 data_t& usernameData, mach_msg_type_number_t& usernameLength, data_t& passwordData, mach_msg_type_number_t& passwordLength) 1580{ 1581 WTF::CString username; 1582 WTF::CString password; 1583 1584 if (!WebKit::getAuthenticationInfo(protocolData, hostData, port, schemeData, realmData, username, password)) 1585 return false; 1586 1587 usernameLength = username.length(); 1588 mig_allocate(reinterpret_cast<vm_address_t*>(&usernameData), usernameLength); 1589 memcpy(usernameData, username.data(), usernameLength); 1590 1591 passwordLength = password.length(); 1592 mig_allocate(reinterpret_cast<vm_address_t*>(&passwordData), passwordLength); 1593 memcpy(passwordData, password.data(), passwordLength); 1594 1595 return true; 1596} 1597 1598bool NetscapePluginInstanceProxy::convertPoint(double sourceX, double sourceY, NPCoordinateSpace sourceSpace, 1599 double& destX, double& destY, NPCoordinateSpace destSpace) 1600{ 1601 ASSERT(m_pluginView); 1602 1603 return [m_pluginView convertFromX:sourceX andY:sourceY space:sourceSpace toX:&destX andY:&destY space:destSpace]; 1604} 1605 1606uint32_t NetscapePluginInstanceProxy::checkIfAllowedToLoadURL(const char* url, const char* target) 1607{ 1608 uint32_t checkID; 1609 1610 // Assign a check ID 1611 do { 1612 checkID = ++m_urlCheckCounter; 1613 } while (m_urlChecks.contains(checkID) || !m_urlCheckCounter); 1614 1615 NSString *frameName = target ? [NSString stringWithCString:target encoding:NSISOLatin1StringEncoding] : nil; 1616 1617 NSNumber *contextInfo = [[NSNumber alloc] initWithUnsignedInt:checkID]; 1618 WebPluginContainerCheck *check = [WebPluginContainerCheck checkWithRequest:[m_pluginView requestWithURLCString:url] 1619 target:frameName 1620 resultObject:m_pluginView 1621 selector:@selector(_containerCheckResult:contextInfo:) 1622 controller:m_pluginView 1623 contextInfo:contextInfo]; 1624 1625 [contextInfo release]; 1626 m_urlChecks.set(checkID, check); 1627 [check start]; 1628 1629 return checkID; 1630} 1631 1632void NetscapePluginInstanceProxy::cancelCheckIfAllowedToLoadURL(uint32_t checkID) 1633{ 1634 URLCheckMap::iterator it = m_urlChecks.find(checkID); 1635 if (it == m_urlChecks.end()) 1636 return; 1637 1638 WebPluginContainerCheck *check = it->value.get(); 1639 [check cancel]; 1640 m_urlChecks.remove(it); 1641} 1642 1643void NetscapePluginInstanceProxy::checkIfAllowedToLoadURLResult(uint32_t checkID, bool allowed) 1644{ 1645 _WKPHCheckIfAllowedToLoadURLResult(m_pluginHostProxy->port(), m_pluginID, checkID, allowed); 1646} 1647 1648void NetscapePluginInstanceProxy::resolveURL(const char* url, const char* target, data_t& resolvedURLData, mach_msg_type_number_t& resolvedURLLength) 1649{ 1650 ASSERT(m_pluginView); 1651 1652 WTF::CString resolvedURL = [m_pluginView resolvedURLStringForURL:url target:target]; 1653 1654 resolvedURLLength = resolvedURL.length(); 1655 mig_allocate(reinterpret_cast<vm_address_t*>(&resolvedURLData), resolvedURLLength); 1656 memcpy(resolvedURLData, resolvedURL.data(), resolvedURLLength); 1657} 1658 1659void NetscapePluginInstanceProxy::privateBrowsingModeDidChange(bool isPrivateBrowsingEnabled) 1660{ 1661 _WKPHPluginInstancePrivateBrowsingModeDidChange(m_pluginHostProxy->port(), m_pluginID, isPrivateBrowsingEnabled); 1662} 1663 1664static String& globalExceptionString() 1665{ 1666 DEPRECATED_DEFINE_STATIC_LOCAL(String, exceptionString, ()); 1667 return exceptionString; 1668} 1669 1670void NetscapePluginInstanceProxy::setGlobalException(const String& exception) 1671{ 1672 globalExceptionString() = exception; 1673} 1674 1675void NetscapePluginInstanceProxy::moveGlobalExceptionToExecState(ExecState* exec) 1676{ 1677 if (globalExceptionString().isNull()) 1678 return; 1679 1680 { 1681 JSLockHolder lock(exec); 1682 exec->vm().throwException(exec, createError(exec, globalExceptionString())); 1683 } 1684 1685 globalExceptionString() = String(); 1686} 1687 1688} // namespace WebKit 1689 1690#endif // USE(PLUGIN_HOST_PROCESS) && ENABLE(NETSCAPE_PLUGIN_API) 1691