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