Document::securityOrigin() should return a reference.
[WebKit-https.git] / Source / WebKit / win / Plugins / PluginView.cpp
1 /*
2  * Copyright (C) 2006-2017 Apple Inc. All rights reserved.
3  * Copyright (C) 2008 Collabora Ltd. All rights reserved.
4  * Copyright (C) 2010 Girish Ramakrishnan <girish@forwardbias.in>
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
16  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
19  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
23  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
26  */
27
28 #include "config.h"
29 #include "PluginView.h"
30
31 #include "PluginDatabase.h"
32 #include "PluginDebug.h"
33 #include "PluginPackage.h"
34 #include "WebFrameLoaderClient.h"
35 #include <WebCore/BridgeJSC.h>
36 #include <WebCore/Chrome.h>
37 #include <WebCore/CommonVM.h>
38 #include <WebCore/CookieJar.h>
39 #include <WebCore/Document.h>
40 #include <WebCore/DocumentLoader.h>
41 #include <WebCore/Element.h>
42 #include <WebCore/EventNames.h>
43 #include <WebCore/FocusController.h>
44 #include <WebCore/Frame.h>
45 #include <WebCore/FrameLoadRequest.h>
46 #include <WebCore/FrameLoader.h>
47 #include <WebCore/FrameLoaderClient.h>
48 #include <WebCore/FrameTree.h>
49 #include <WebCore/FrameView.h>
50 #include <WebCore/GraphicsContext.h>
51 #include <WebCore/HTMLNames.h>
52 #include <WebCore/HTMLPlugInElement.h>
53 #include <WebCore/HTTPHeaderNames.h>
54 #include <WebCore/Image.h>
55 #include <WebCore/JSDOMBinding.h>
56 #include <WebCore/JSDOMWindow.h>
57 #include <WebCore/KeyboardEvent.h>
58 #include <WebCore/MIMETypeRegistry.h>
59 #include <WebCore/MouseEvent.h>
60 #include <WebCore/NP_jsobject.h>
61 #include <WebCore/NotImplemented.h>
62 #include <WebCore/Page.h>
63 #include <WebCore/PlatformMouseEvent.h>
64 #include <WebCore/ProxyServer.h>
65 #include <WebCore/RenderBox.h>
66 #include <WebCore/RenderObject.h>
67 #include <WebCore/ScriptController.h>
68 #include <WebCore/SecurityOrigin.h>
69 #include <WebCore/Settings.h>
70 #include <WebCore/UserGestureIndicator.h>
71 #include <WebCore/WheelEvent.h>
72 #include <WebCore/c_instance.h>
73 #include <WebCore/npruntime_impl.h>
74 #include <WebCore/runtime_root.h>
75 #include <bindings/ScriptValue.h>
76 #include <runtime/JSCJSValue.h>
77 #include <runtime/JSLock.h>
78 #include <wtf/ASCIICType.h>
79 #include <wtf/text/WTFString.h>
80
81 #if ENABLE(NETSCAPE_PLUGIN_API)
82 #include "PluginMainThreadScheduler.h"
83 #include "PluginMessageThrottlerWin.h"
84 #endif
85
86 using JSC::ExecState;
87 using JSC::JSLock;
88 using JSC::JSObject;
89 using JSC::JSValue;
90
91 #if ENABLE(NETSCAPE_PLUGIN_API)
92
93 using std::min;
94
95 using namespace WTF;
96
97 namespace WebCore {
98
99 using namespace HTMLNames;
100
101 static int s_callingPlugin;
102
103 typedef HashMap<NPP, PluginView*> InstanceMap;
104
105 static InstanceMap& instanceMap()
106 {
107     static InstanceMap& map = *new InstanceMap;
108     return map;
109 }
110
111 static String scriptStringIfJavaScriptURL(const URL& url)
112 {
113     if (!protocolIsJavaScript(url))
114         return String();
115
116     // This returns an unescaped string
117     return decodeURLEscapeSequences(url.string().substring(11));
118 }
119
120 PluginView* PluginView::s_currentPluginView = 0;
121
122 void PluginView::popPopupsStateTimerFired()
123 {
124     popPopupsEnabledState();
125 }
126
127 IntRect PluginView::windowClipRect() const
128 {
129     // Start by clipping to our bounds.
130     IntRect clipRect(m_windowRect);
131     
132     // Take our element and get the clip rect from the enclosing layer and frame view.
133     FrameView* parentView = m_element->document().view();
134     IntRect windowClipRect = parentView->windowClipRectForFrameOwner(m_element, true);
135     windowClipRect.scale(deviceScaleFactor());
136     clipRect.intersect(windowClipRect);
137
138     return clipRect;
139 }
140
141 void PluginView::setFrameRect(const IntRect& rect)
142 {
143     if (m_element->document().printing())
144         return;
145
146     if (rect != frameRect())
147         Widget::setFrameRect(rect);
148
149     updatePluginWidget();
150
151     // On Windows always call plugin to change geometry.
152     setNPWindowRect(rect);
153 }
154
155 void PluginView::frameRectsChanged()
156 {
157     updatePluginWidget();
158 }
159
160 void PluginView::clipRectChanged()
161 {
162     updatePluginWidget();
163 }
164
165 void PluginView::handleEvent(Event* event)
166 {
167     if (!m_plugin || m_isWindowed)
168         return;
169
170     // Protect the plug-in from deletion while dispatching the event.
171     RefPtr<PluginView> protect(this);
172
173     if (event->isMouseEvent())
174         handleMouseEvent(static_cast<MouseEvent*>(event));
175     else if (event->isKeyboardEvent())
176         handleKeyboardEvent(static_cast<KeyboardEvent*>(event));
177     else if (event->type() == eventNames().contextmenuEvent)
178         event->setDefaultHandled(); // We don't know if the plug-in has handled mousedown event by displaying a context menu, so we never want WebKit to show a default one.
179 }
180
181 void PluginView::init()
182 {
183     if (m_haveInitialized)
184         return;
185
186     m_haveInitialized = true;
187
188     if (!m_plugin) {
189         ASSERT(m_status == PluginStatusCanNotFindPlugin);
190         return;
191     }
192
193     LOG(Plugins, "PluginView::init(): Initializing plug-in '%s'", m_plugin->name().utf8().data());
194
195     if (!m_plugin->load()) {
196         m_plugin = nullptr;
197         m_status = PluginStatusCanNotLoadPlugin;
198         return;
199     }
200
201     if (!startOrAddToUnstartedList()) {
202         m_status = PluginStatusCanNotLoadPlugin;
203         return;
204     }
205
206     m_status = PluginStatusLoadedSuccessfully;
207 }
208
209 bool PluginView::startOrAddToUnstartedList()
210 {
211     if (!m_parentFrame->page())
212         return false;
213
214     // We only delay starting the plug-in if we're going to kick off the load
215     // ourselves. Otherwise, the loader will try to deliver data before we've
216     // started the plug-in.
217     if (!m_loadManually && !m_parentFrame->page()->canStartMedia()) {
218         m_parentFrame->document()->addMediaCanStartListener(this);
219         m_isWaitingToStart = true;
220         return true;
221     }
222
223     return start();
224 }
225
226 bool PluginView::start()
227 {
228     if (m_isStarted)
229         return false;
230
231     m_isWaitingToStart = false;
232
233     PluginMainThreadScheduler::scheduler().registerPlugin(m_instance);
234
235     ASSERT(m_plugin);
236     ASSERT(m_plugin->pluginFuncs()->newp);
237
238     NPError npErr;
239     {
240         PluginView::setCurrentPluginView(this);
241         JSC::JSLock::DropAllLocks dropAllLocks(commonVM());
242         setCallingPlugin(true);
243         npErr = m_plugin->pluginFuncs()->newp((NPMIMEType)m_mimeType.utf8().data(), m_instance, m_mode, m_paramCount, m_paramNames, m_paramValues, NULL);
244         setCallingPlugin(false);
245         LOG_NPERROR(npErr);
246         PluginView::setCurrentPluginView(0);
247     }
248
249     if (npErr != NPERR_NO_ERROR) {
250         m_status = PluginStatusCanNotLoadPlugin;
251         PluginMainThreadScheduler::scheduler().unregisterPlugin(m_instance);
252         return false;
253     }
254
255     m_isStarted = true;
256
257     if (!m_url.isEmpty() && !m_loadManually) {
258         FrameLoadRequest frameLoadRequest(m_parentFrame->document()->securityOrigin(), LockHistory::No, LockBackForwardList::No, ShouldSendReferrer::MaybeSendReferrer, AllowNavigationToInvalidURL::Yes, NewFrameOpenerPolicy::Allow, ShouldOpenExternalURLsPolicy::ShouldNotAllow);
259         frameLoadRequest.resourceRequest().setHTTPMethod("GET");
260         frameLoadRequest.resourceRequest().setURL(m_url);
261         load(frameLoadRequest, false, 0);
262     }
263
264     m_status = PluginStatusLoadedSuccessfully;
265
266     if (!platformStart())
267         m_status = PluginStatusCanNotLoadPlugin;
268
269     if (m_status != PluginStatusLoadedSuccessfully)
270         return false;
271
272     return true;
273 }
274
275 void PluginView::mediaCanStart(Document&)
276 {
277     ASSERT(!m_isStarted);
278     if (!start())
279         static_cast<WebFrameLoaderClient&>(parentFrame()->loader().client()).dispatchDidFailToStartPlugin(this);
280 }
281
282 PluginView::~PluginView()
283 {
284     LOG(Plugins, "PluginView::~PluginView()");
285
286     ASSERT(!m_lifeSupportTimer.isActive());
287
288     // If we failed to find the plug-in, we'll return early in our constructor, and
289     // m_instance will be 0.
290     if (m_instance)
291         instanceMap().remove(m_instance);
292
293     if (m_isWaitingToStart)
294         m_parentFrame->document()->removeMediaCanStartListener(this);
295
296     stop();
297
298     if (m_elementNPObject)
299         _NPN_ReleaseObject(m_elementNPObject);
300     
301     freeStringArray(m_paramNames, m_paramCount);
302     freeStringArray(m_paramValues, m_paramCount);
303
304     platformDestroy();
305
306     m_parentFrame->script().cleanupScriptObjectsForPlugin(this);
307
308     if (m_plugin && !(m_plugin->quirks().contains(PluginQuirkDontUnloadPlugin)))
309         m_plugin->unload();
310 }
311
312 void PluginView::stop()
313 {
314     if (!m_isStarted)
315         return;
316
317     LOG(Plugins, "PluginView::stop(): Stopping plug-in '%s'", m_plugin->name().utf8().data());
318
319     HashSet<RefPtr<PluginStream> > streams = m_streams;
320     HashSet<RefPtr<PluginStream> >::iterator end = streams.end();
321     for (HashSet<RefPtr<PluginStream> >::iterator it = streams.begin(); it != end; ++it) {
322         (*it)->stop();
323         disconnectStream((*it).get());
324     }
325
326     ASSERT(m_streams.isEmpty());
327
328     m_isStarted = false;
329
330     JSC::JSLock::DropAllLocks dropAllLocks(commonVM());
331
332 #if ENABLE(NETSCAPE_PLUGIN_API)
333     // Unsubclass the window
334     if (m_isWindowed) {
335         WNDPROC currentWndProc = (WNDPROC)GetWindowLongPtr(platformPluginWidget(), GWLP_WNDPROC);
336
337         if (currentWndProc == PluginViewWndProc)
338             SetWindowLongPtr(platformPluginWidget(), GWLP_WNDPROC, (LONG_PTR)m_pluginWndProc);
339     }
340 #endif // ENABLE(NETSCAPE_PLUGIN_API)
341
342     // Clear the window
343     m_npWindow.window = 0;
344
345     if (m_plugin->pluginFuncs()->setwindow && !m_plugin->quirks().contains(PluginQuirkDontSetNullWindowHandleOnDestroy)) {
346         PluginView::setCurrentPluginView(this);
347         setCallingPlugin(true);
348         m_plugin->pluginFuncs()->setwindow(m_instance, &m_npWindow);
349         setCallingPlugin(false);
350         PluginView::setCurrentPluginView(0);
351     }
352
353     PluginMainThreadScheduler::scheduler().unregisterPlugin(m_instance);
354
355     NPSavedData* savedData = 0;
356     PluginView::setCurrentPluginView(this);
357     setCallingPlugin(true);
358     NPError npErr = m_plugin->pluginFuncs()->destroy(m_instance, &savedData);
359     setCallingPlugin(false);
360     LOG_NPERROR(npErr);
361     PluginView::setCurrentPluginView(0);
362
363 #if ENABLE(NETSCAPE_PLUGIN_API)
364     if (savedData) {
365         // TODO: Actually save this data instead of just discarding it
366         if (savedData->buf)
367             NPN_MemFree(savedData->buf);
368         NPN_MemFree(savedData);
369     }
370 #endif
371
372     m_instance->pdata = 0;
373 }
374
375 void PluginView::setCurrentPluginView(PluginView* pluginView)
376 {
377     s_currentPluginView = pluginView;
378 }
379
380 PluginView* PluginView::currentPluginView()
381 {
382     return s_currentPluginView;
383 }
384
385 static char* createUTF8String(const String& str)
386 {
387     CString cstr = str.utf8();
388     const size_t cstrLength = cstr.length();
389     char* result = reinterpret_cast<char*>(fastMalloc(cstrLength + 1));
390
391     memcpy(result, cstr.data(), cstrLength);
392     result[cstrLength] = '\0';
393
394     return result;
395 }
396
397 void PluginView::performRequest(PluginRequest* request)
398 {
399     if (!m_isStarted)
400         return;
401
402     // don't let a plugin start any loads if it is no longer part of a document that is being 
403     // displayed unless the loads are in the same frame as the plugin.
404     const String& targetFrameName = request->frameLoadRequest().frameName();
405     if (m_parentFrame->loader().documentLoader() != m_parentFrame->loader().activeDocumentLoader() && (targetFrameName.isNull() || m_parentFrame->tree().find(targetFrameName) != m_parentFrame))
406         return;
407
408     URL requestURL = request->frameLoadRequest().resourceRequest().url();
409     String jsString = scriptStringIfJavaScriptURL(requestURL);
410
411     UserGestureIndicator gestureIndicator(request->shouldAllowPopups() ? std::optional<ProcessingUserGestureState>(ProcessingUserGesture) : std::nullopt);
412
413     if (jsString.isNull()) {
414         // if this is not a targeted request, create a stream for it. otherwise,
415         // just pass it off to the loader
416         if (targetFrameName.isEmpty()) {
417             RefPtr<PluginStream> stream = PluginStream::create(this, m_parentFrame.get(), request->frameLoadRequest().resourceRequest(), request->sendNotification(), request->notifyData(), plugin()->pluginFuncs(), instance(), m_plugin->quirks());
418             m_streams.add(stream);
419             stream->start();
420         } else {
421             // If the target frame is our frame, we could destroy the
422             // PluginView, so we protect it. <rdar://problem/6991251>
423             RefPtr<PluginView> protect(this);
424
425             FrameLoadRequest frameRequest(m_parentFrame.get(), request->frameLoadRequest().resourceRequest(), ShouldOpenExternalURLsPolicy::ShouldNotAllow);
426             frameRequest.setFrameName(targetFrameName);
427             frameRequest.setShouldCheckNewWindowPolicy(true);
428             m_parentFrame->loader().load(frameRequest);
429
430             // FIXME: <rdar://problem/4807469> This should be sent when the document has finished loading
431             if (request->sendNotification()) {
432                 PluginView::setCurrentPluginView(this);
433                 JSC::JSLock::DropAllLocks dropAllLocks(commonVM());
434                 setCallingPlugin(true);
435                 m_plugin->pluginFuncs()->urlnotify(m_instance, requestURL.string().utf8().data(), NPRES_DONE, request->notifyData());
436                 setCallingPlugin(false);
437                 PluginView::setCurrentPluginView(0);
438             }
439         }
440         return;
441     }
442
443     // Targeted JavaScript requests are only allowed on the frame that contains the JavaScript plugin
444     // and this has been made sure in ::load.
445     ASSERT(targetFrameName.isEmpty() || m_parentFrame->tree().find(targetFrameName) == m_parentFrame);
446     
447     // Executing a script can cause the plugin view to be destroyed, so we keep a reference to it.
448     RefPtr<PluginView> protector(this);
449     auto result = m_parentFrame->script().executeScript(jsString, request->shouldAllowPopups());
450
451     if (targetFrameName.isNull()) {
452         CString cstr;
453         {
454             JSC::ExecState& state = *m_parentFrame->script().globalObject(pluginWorld())->globalExec();
455             JSC::JSLockHolder lock(&state);
456             String resultString;
457             if (result && result.getString(&state, resultString))
458                 cstr = resultString.utf8();
459         }
460
461         RefPtr<PluginStream> stream = PluginStream::create(this, m_parentFrame.get(), request->frameLoadRequest().resourceRequest(), request->sendNotification(), request->notifyData(), plugin()->pluginFuncs(), instance(), m_plugin->quirks());
462         m_streams.add(stream);
463         stream->sendJavaScriptStream(requestURL, cstr);
464     }
465 }
466
467 void PluginView::requestTimerFired()
468 {
469     ASSERT(!m_requests.isEmpty());
470     ASSERT(!m_isJavaScriptPaused);
471
472     std::unique_ptr<PluginRequest> request = WTFMove(m_requests[0]);
473     m_requests.remove(0);
474     
475     // Schedule a new request before calling performRequest since the call to
476     // performRequest can cause the plugin view to be deleted.
477     if (!m_requests.isEmpty())
478         m_requestTimer.startOneShot(0);
479
480     performRequest(request.get());
481 }
482
483 void PluginView::scheduleRequest(std::unique_ptr<PluginRequest> request)
484 {
485     m_requests.append(WTFMove(request));
486
487     if (!m_isJavaScriptPaused)
488         m_requestTimer.startOneShot(0);
489 }
490
491 NPError PluginView::load(const FrameLoadRequest& frameLoadRequest, bool sendNotification, void* notifyData)
492 {
493     ASSERT(frameLoadRequest.resourceRequest().httpMethod() == "GET" || frameLoadRequest.resourceRequest().httpMethod() == "POST");
494
495     URL url = frameLoadRequest.resourceRequest().url();
496     
497     if (url.isEmpty())
498         return NPERR_INVALID_URL;
499
500     // Don't allow requests to be made when the document loader is stopping all loaders.
501     DocumentLoader* loader = m_parentFrame->loader().documentLoader();
502     if (!loader || loader->isStopping())
503         return NPERR_GENERIC_ERROR;
504
505     const String& targetFrameName = frameLoadRequest.frameName();
506     String jsString = scriptStringIfJavaScriptURL(url);
507
508     if (!jsString.isNull()) {
509         // Return NPERR_GENERIC_ERROR if JS is disabled. This is what Mozilla does.
510         if (!m_parentFrame->script().canExecuteScripts(NotAboutToExecuteScript))
511             return NPERR_GENERIC_ERROR;
512
513         // For security reasons, only allow JS requests to be made on the frame that contains the plug-in.
514         if (!targetFrameName.isNull() && m_parentFrame->tree().find(targetFrameName) != m_parentFrame)
515             return NPERR_INVALID_PARAM;
516     } else if (!m_parentFrame->document()->securityOrigin().canDisplay(url))
517         return NPERR_GENERIC_ERROR;
518
519     scheduleRequest(std::make_unique<PluginRequest>(frameLoadRequest, sendNotification, notifyData, arePopupsAllowed()));
520
521     return NPERR_NO_ERROR;
522 }
523
524 static URL makeURL(const URL& baseURL, const char* relativeURLString)
525 {
526     String urlString = relativeURLString;
527
528     // Strip return characters.
529     urlString.replaceWithLiteral('\n', "");
530     urlString.replaceWithLiteral('\r', "");
531
532     return URL(baseURL, urlString);
533 }
534
535 NPError PluginView::getURLNotify(const char* url, const char* target, void* notifyData)
536 {
537     FrameLoadRequest frameLoadRequest(m_parentFrame->document()->securityOrigin(), LockHistory::No, LockBackForwardList::No, ShouldSendReferrer::MaybeSendReferrer, AllowNavigationToInvalidURL::Yes, NewFrameOpenerPolicy::Allow, ShouldOpenExternalURLsPolicy::ShouldNotAllow);
538
539     frameLoadRequest.setFrameName(target);
540     frameLoadRequest.resourceRequest().setHTTPMethod("GET");
541     frameLoadRequest.resourceRequest().setURL(makeURL(m_parentFrame->document()->baseURL(), url));
542
543     return load(frameLoadRequest, true, notifyData);
544 }
545
546 NPError PluginView::getURL(const char* url, const char* target)
547 {
548     FrameLoadRequest frameLoadRequest(m_parentFrame->document()->securityOrigin(), LockHistory::No, LockBackForwardList::No, ShouldSendReferrer::MaybeSendReferrer, AllowNavigationToInvalidURL::Yes, NewFrameOpenerPolicy::Allow, ShouldOpenExternalURLsPolicy::ShouldNotAllow);
549
550     frameLoadRequest.setFrameName(target);
551     frameLoadRequest.resourceRequest().setHTTPMethod("GET");
552     frameLoadRequest.resourceRequest().setURL(makeURL(m_parentFrame->document()->baseURL(), url));
553
554     return load(frameLoadRequest, false, 0);
555 }
556
557 NPError PluginView::postURLNotify(const char* url, const char* target, uint32_t len, const char* buf, NPBool file, void* notifyData)
558 {
559     return handlePost(url, target, len, buf, file, notifyData, true, true);
560 }
561
562 NPError PluginView::postURL(const char* url, const char* target, uint32_t len, const char* buf, NPBool file)
563 {
564     // As documented, only allow headers to be specified via NPP_PostURL when using a file.
565     return handlePost(url, target, len, buf, file, 0, false, file);
566 }
567
568 NPError PluginView::newStream(NPMIMEType, const char* /* target */, NPStream**)
569 {
570     notImplemented();
571     // Unsupported
572     return NPERR_GENERIC_ERROR;
573 }
574
575 int32_t PluginView::write(NPStream*, int32_t /* len */, void* /* buffer */)
576 {
577     notImplemented();
578     // Unsupported
579     return -1;
580 }
581
582 NPError PluginView::destroyStream(NPStream* stream, NPReason reason)
583 {
584     if (!stream || PluginStream::ownerForStream(stream) != m_instance)
585         return NPERR_INVALID_INSTANCE_ERROR;
586
587     PluginStream* browserStream = static_cast<PluginStream*>(stream->ndata);
588     browserStream->cancelAndDestroyStream(reason);
589
590     return NPERR_NO_ERROR;
591 }
592
593 void PluginView::status(const char* message)
594 {
595     if (Page* page = m_parentFrame->page())
596         page->chrome().setStatusbarText(m_parentFrame.get(), String::fromUTF8(message));
597 }
598
599 NPError PluginView::setValue(NPPVariable variable, void* value)
600 {
601     LOG(Plugins, "PluginView::setValue(%s): ", prettyNameForNPPVariable(variable, value).data());
602
603     switch (variable) {
604     case NPPVpluginWindowBool:
605         m_isWindowed = value;
606         return NPERR_NO_ERROR;
607     case NPPVpluginTransparentBool:
608         m_isTransparent = value;
609         return NPERR_NO_ERROR;
610     default:
611         notImplemented();
612         return NPERR_GENERIC_ERROR;
613     }
614 }
615
616 void PluginView::invalidateTimerFired()
617 {
618     for (unsigned i = 0; i < m_invalidRects.size(); i++)
619         invalidateRect(m_invalidRects[i]);
620     m_invalidRects.clear();
621 }
622
623
624 void PluginView::pushPopupsEnabledState(bool state)
625 {
626     m_popupStateStack.append(state);
627 }
628  
629 void PluginView::popPopupsEnabledState()
630 {
631     m_popupStateStack.removeLast();
632 }
633
634 bool PluginView::arePopupsAllowed() const
635 {
636     if (!m_popupStateStack.isEmpty())
637         return m_popupStateStack.last();
638
639     return false;
640 }
641
642 void PluginView::setJavaScriptPaused(bool paused)
643 {
644     if (m_isJavaScriptPaused == paused)
645         return;
646     m_isJavaScriptPaused = paused;
647
648     if (m_isJavaScriptPaused)
649         m_requestTimer.stop();
650     else if (!m_requests.isEmpty())
651         m_requestTimer.startOneShot(0);
652 }
653
654 #if ENABLE(NETSCAPE_PLUGIN_API)
655 NPObject* PluginView::npObject()
656 {
657     NPObject* object = 0;
658
659     if (!m_isStarted || !m_plugin || !m_plugin->pluginFuncs()->getvalue)
660         return 0;
661
662     // On Windows, calling Java's NPN_GetValue can allow the message loop to
663     // run, allowing loading to take place or JavaScript to run. Protect the
664     // PluginView from destruction. <rdar://problem/6978804>
665     RefPtr<PluginView> protect(this);
666
667     NPError npErr;
668     {
669         PluginView::setCurrentPluginView(this);
670         JSC::JSLock::DropAllLocks dropAllLocks(commonVM());
671         setCallingPlugin(true);
672         npErr = m_plugin->pluginFuncs()->getvalue(m_instance, NPPVpluginScriptableNPObject, &object);
673         setCallingPlugin(false);
674         PluginView::setCurrentPluginView(0);
675     }
676
677     if (npErr != NPERR_NO_ERROR)
678         return 0;
679
680     return object;
681 }
682 #endif
683
684 RefPtr<JSC::Bindings::Instance> PluginView::bindingInstance()
685 {
686 #if ENABLE(NETSCAPE_PLUGIN_API)
687     NPObject* object = npObject();
688     if (!object)
689         return nullptr;
690
691     if (hasOneRef()) {
692         // The renderer for the PluginView was destroyed during the above call, and
693         // the PluginView will be destroyed when this function returns, so we
694         // return null.
695         return nullptr;
696     }
697
698     RefPtr<JSC::Bindings::RootObject> root = m_parentFrame->script().createRootObject(this);
699     RefPtr<JSC::Bindings::Instance> instance = JSC::Bindings::CInstance::create(object, root.release());
700
701     _NPN_ReleaseObject(object);
702
703     return instance;
704 #else
705     return nullptr;
706 #endif
707 }
708
709 void PluginView::disconnectStream(PluginStream* stream)
710 {
711     ASSERT(m_streams.contains(stream));
712
713     m_streams.remove(stream);
714 }
715
716 void PluginView::setParameters(const Vector<String>& paramNames, const Vector<String>& paramValues)
717 {
718     ASSERT(paramNames.size() == paramValues.size());
719
720     unsigned size = paramNames.size();
721     unsigned paramCount = 0;
722
723     m_paramNames = reinterpret_cast<char**>(fastMalloc(sizeof(char*) * size));
724     m_paramValues = reinterpret_cast<char**>(fastMalloc(sizeof(char*) * size));
725
726     for (unsigned i = 0; i < size; i++) {
727         if (m_plugin->quirks().contains(PluginQuirkRemoveWindowlessVideoParam) && equalLettersIgnoringASCIICase(paramNames[i], "windowlessvideo"))
728             continue;
729
730         if (paramNames[i] == "pluginspage")
731             m_pluginsPage = paramValues[i];
732
733         m_paramNames[paramCount] = createUTF8String(paramNames[i]);
734         m_paramValues[paramCount] = createUTF8String(paramValues[i]);
735
736         paramCount++;
737     }
738
739     m_paramCount = paramCount;
740 }
741
742 PluginView::PluginView(Frame* parentFrame, const IntSize& size, PluginPackage* plugin, HTMLPlugInElement* element, const URL& url, const Vector<String>& paramNames, const Vector<String>& paramValues, const String& mimeType, bool loadManually)
743     : m_parentFrame(parentFrame)
744     , m_plugin(plugin)
745     , m_element(element)
746     , m_isStarted(false)
747     , m_url(url)
748     , m_status(PluginStatusLoadedSuccessfully)
749     , m_requestTimer(*this, &PluginView::requestTimerFired)
750     , m_invalidateTimer(*this, &PluginView::invalidateTimerFired)
751     , m_popPopupsStateTimer(*this, &PluginView::popPopupsStateTimerFired)
752     , m_lifeSupportTimer(*this, &PluginView::lifeSupportTimerFired)
753     , m_mode(loadManually ? NP_FULL : NP_EMBED)
754     , m_paramNames(0)
755     , m_paramValues(0)
756     , m_mimeType(mimeType)
757     , m_instance(0)
758     , m_elementNPObject(nullptr)
759     , m_isWindowed(true)
760     , m_isTransparent(false)
761     , m_haveInitialized(false)
762     , m_isWaitingToStart(false)
763 #if ENABLE(NETSCAPE_PLUGIN_API)
764     , m_pluginWndProc(0)
765     , m_lastMessage(0)
766     , m_isCallingPluginWndProc(false)
767     , m_wmPrintHDC(0)
768     , m_haveUpdatedPluginWidget(false)
769 #endif
770     , m_loadManually(loadManually)
771     , m_manualStream(0)
772     , m_isJavaScriptPaused(false)
773     , m_haveCalledSetWindow(false)
774 {
775     if (!m_plugin) {
776         m_status = PluginStatusCanNotFindPlugin;
777         return;
778     }
779
780     m_instance = &m_instanceStruct;
781     m_instance->ndata = this;
782     m_instance->pdata = 0;
783
784     instanceMap().add(m_instance, this);
785
786     setParameters(paramNames, paramValues);
787
788     memset(&m_npWindow, 0, sizeof(m_npWindow));
789
790     resize(size);
791 }
792
793 void PluginView::focusPluginElement()
794 {
795     if (Page* page = m_parentFrame->page())
796         page->focusController().setFocusedElement(m_element, m_parentFrame);
797     else
798         m_parentFrame->document()->setFocusedElement(m_element);
799 }
800
801 void PluginView::didReceiveResponse(const ResourceResponse& response)
802 {
803     if (m_status != PluginStatusLoadedSuccessfully)
804         return;
805
806     ASSERT(m_loadManually);
807     ASSERT(!m_manualStream);
808
809     m_manualStream = PluginStream::create(this, m_parentFrame.get(), m_parentFrame->loader().activeDocumentLoader()->request(), false, 0, plugin()->pluginFuncs(), instance(), m_plugin->quirks());
810     m_manualStream->setLoadManually(true);
811
812     m_manualStream->didReceiveResponse(0, response);
813 }
814
815 void PluginView::didReceiveData(const char* data, int length)
816 {
817     if (m_status != PluginStatusLoadedSuccessfully)
818         return;
819
820     ASSERT(m_loadManually);
821     ASSERT(m_manualStream);
822     
823     m_manualStream->didReceiveData(0, data, length);
824 }
825
826 void PluginView::didFinishLoading()
827 {
828     if (m_status != PluginStatusLoadedSuccessfully)
829         return;
830
831     ASSERT(m_loadManually);
832     ASSERT(m_manualStream);
833
834     m_manualStream->didFinishLoading(0);
835 }
836
837 void PluginView::didFail(const ResourceError& error)
838 {
839     if (m_status != PluginStatusLoadedSuccessfully)
840         return;
841
842     ASSERT(m_loadManually);
843     
844     if (m_manualStream)
845         m_manualStream->didFail(0, error);
846 }
847
848 void PluginView::setCallingPlugin(bool b) const
849 {
850     if (!m_plugin->quirks().contains(PluginQuirkHasModalMessageLoop))
851         return;
852
853     if (b)
854         ++s_callingPlugin;
855     else
856         --s_callingPlugin;
857
858     ASSERT(s_callingPlugin >= 0);
859 }
860
861 bool PluginView::isCallingPlugin()
862 {
863     return s_callingPlugin > 0;
864 }
865
866 Ref<PluginView> PluginView::create(Frame* parentFrame, const IntSize& size, HTMLPlugInElement* element, const URL& url, const Vector<String>& paramNames, const Vector<String>& paramValues, const String& mimeType, bool loadManually)
867 {
868     // if we fail to find a plugin for this MIME type, findPlugin will search for
869     // a plugin by the file extension and update the MIME type, so pass a mutable String
870     String mimeTypeCopy = mimeType;
871     PluginPackage* plugin = PluginDatabase::installedPlugins()->findPlugin(url, mimeTypeCopy);
872
873     // No plugin was found, try refreshing the database and searching again
874     if (!plugin && PluginDatabase::installedPlugins()->refresh()) {
875         mimeTypeCopy = mimeType;
876         plugin = PluginDatabase::installedPlugins()->findPlugin(url, mimeTypeCopy);
877     }
878
879     return adoptRef(*new PluginView(parentFrame, size, plugin, element, url, paramNames, paramValues, mimeTypeCopy, loadManually));
880 }
881
882 void PluginView::freeStringArray(char** stringArray, int length)
883 {
884     if (!stringArray)
885         return;
886
887     for (int i = 0; i < length; i++)
888         fastFree(stringArray[i]);
889
890     fastFree(stringArray);
891 }
892
893 static inline bool startsWithBlankLine(const Vector<char>& buffer)
894 {
895     return buffer.size() > 0 && buffer[0] == '\n';
896 }
897
898 static inline int locationAfterFirstBlankLine(const Vector<char>& buffer)
899 {
900     const char* bytes = buffer.data();
901     unsigned length = buffer.size();
902
903     for (unsigned i = 0; i < length - 4; i++) {
904         // Support for Acrobat. It sends "\n\n".
905         if (bytes[i] == '\n' && bytes[i + 1] == '\n')
906             return i + 2;
907         
908         // Returns the position after 2 CRLF's or 1 CRLF if it is the first line.
909         if (bytes[i] == '\r' && bytes[i + 1] == '\n') {
910             i += 2;
911             if (i == 2)
912                 return i;
913             else if (bytes[i] == '\n')
914                 // Support for Director. It sends "\r\n\n" (3880387).
915                 return i + 1;
916             else if (bytes[i] == '\r' && bytes[i + 1] == '\n')
917                 // Support for Flash. It sends "\r\n\r\n" (3758113).
918                 return i + 2;
919         }
920     }
921
922     return -1;
923 }
924
925 static inline const char* findEOL(const char* bytes, unsigned length)
926 {
927     // According to the HTTP specification EOL is defined as
928     // a CRLF pair. Unfortunately, some servers will use LF
929     // instead. Worse yet, some servers will use a combination
930     // of both (e.g. <header>CRLFLF<body>), so findEOL needs
931     // to be more forgiving. It will now accept CRLF, LF or
932     // CR.
933     //
934     // It returns NULL if EOLF is not found or it will return
935     // a pointer to the first terminating character.
936     for (unsigned i = 0; i < length; i++) {
937         if (bytes[i] == '\n')
938             return bytes + i;
939         if (bytes[i] == '\r') {
940             // Check to see if spanning buffer bounds
941             // (CRLF is across reads). If so, wait for
942             // next read.
943             if (i + 1 == length)
944                 break;
945
946             return bytes + i;
947         }
948     }
949
950     return 0;
951 }
952
953 static inline String capitalizeRFC822HeaderFieldName(const String& name)
954 {
955     bool capitalizeCharacter = true;
956     String result;
957
958     for (unsigned i = 0; i < name.length(); i++) {
959         UChar c;
960
961         if (capitalizeCharacter && name[i] >= 'a' && name[i] <= 'z')
962             c = toASCIIUpper(name[i]);
963         else if (!capitalizeCharacter && name[i] >= 'A' && name[i] <= 'Z')
964             c = toASCIILower(name[i]);
965         else
966             c = name[i];
967
968         if (name[i] == '-')
969             capitalizeCharacter = true;
970         else
971             capitalizeCharacter = false;
972
973         result.append(c);
974     }
975
976     return result;
977 }
978
979 static inline HTTPHeaderMap parseRFC822HeaderFields(const Vector<char>& buffer, unsigned length)
980 {
981     const char* bytes = buffer.data();
982     const char* eol;
983     String lastKey;
984     HTTPHeaderMap headerFields;
985
986     // Loop ove rlines until we're past the header, or we can't find any more end-of-lines
987     while ((eol = findEOL(bytes, length))) {
988         const char* line = bytes;
989         int lineLength = eol - bytes;
990         
991         // Move bytes to the character after the terminator as returned by findEOL.
992         bytes = eol + 1;
993         if ((*eol == '\r') && (*bytes == '\n'))
994             bytes++; // Safe since findEOL won't return a spanning CRLF.
995
996         length -= (bytes - line);
997         if (lineLength == 0)
998             // Blank line; we're at the end of the header
999             break;
1000         else if (*line == ' ' || *line == '\t') {
1001             // Continuation of the previous header
1002             if (lastKey.isNull()) {
1003                 // malformed header; ignore it and continue
1004                 continue;
1005             } else {
1006                 // Merge the continuation of the previous header
1007                 String currentValue = headerFields.get(lastKey);
1008                 String newValue(line, lineLength);
1009
1010                 headerFields.set(lastKey, currentValue + newValue);
1011             }
1012         } else {
1013             // Brand new header
1014             const char* colon;
1015             for (colon = line; *colon != ':' && colon != eol; colon++) {
1016                 // empty loop
1017             }
1018             if (colon == eol) 
1019                 // malformed header; ignore it and continue
1020                 continue;
1021             else {
1022                 lastKey = capitalizeRFC822HeaderFieldName(String(line, colon - line));
1023                 String value;
1024
1025                 for (colon++; colon != eol; colon++) {
1026                     if (*colon != ' ' && *colon != '\t')
1027                         break;
1028                 }
1029                 if (colon == eol)
1030                     value = emptyString();
1031                 else
1032                     value = String(colon, eol - colon);
1033
1034                 String oldValue = headerFields.get(lastKey);
1035                 if (!oldValue.isNull())
1036                     value = oldValue + ", " + value;
1037
1038                 headerFields.set(lastKey, value);
1039             }
1040         }
1041     }
1042
1043     return headerFields;
1044 }
1045
1046 NPError PluginView::handlePost(const char* url, const char* target, uint32_t len, const char* buf, bool file, void* notifyData, bool sendNotification, bool allowHeaders)
1047 {
1048     if (!url || !len || !buf)
1049         return NPERR_INVALID_PARAM;
1050
1051     FrameLoadRequest frameLoadRequest(m_parentFrame->document()->securityOrigin(), LockHistory::No, LockBackForwardList::No, ShouldSendReferrer::MaybeSendReferrer, AllowNavigationToInvalidURL::Yes, NewFrameOpenerPolicy::Allow, ShouldOpenExternalURLsPolicy::ShouldNotAllow);
1052
1053     HTTPHeaderMap headerFields;
1054     Vector<char> buffer;
1055     
1056     if (file) {
1057         NPError readResult = handlePostReadFile(buffer, len, buf);
1058         if(readResult != NPERR_NO_ERROR)
1059             return readResult;
1060     } else {
1061         buffer.resize(len);
1062         memcpy(buffer.data(), buf, len);
1063     }
1064
1065     const char* postData = buffer.data();
1066     int postDataLength = buffer.size();
1067
1068     if (allowHeaders) {
1069         if (startsWithBlankLine(buffer)) {
1070             postData++;
1071             postDataLength--;
1072         } else {
1073             int location = locationAfterFirstBlankLine(buffer);
1074             if (location != -1) {
1075                 // If the blank line is somewhere in the middle of the buffer, everything before is the header
1076                 headerFields = parseRFC822HeaderFields(buffer, location);
1077                 unsigned dataLength = buffer.size() - location;
1078
1079                 // Sometimes plugins like to set Content-Length themselves when they post,
1080                 // but WebFoundation does not like that. So we will remove the header
1081                 // and instead truncate the data to the requested length.
1082                 String contentLength = headerFields.get(HTTPHeaderName::ContentLength);
1083
1084                 if (!contentLength.isNull())
1085                     dataLength = min(contentLength.toInt(), (int)dataLength);
1086                 headerFields.remove(HTTPHeaderName::ContentLength);
1087
1088                 postData += location;
1089                 postDataLength = dataLength;
1090             }
1091         }
1092     }
1093
1094     frameLoadRequest.resourceRequest().setHTTPMethod("POST");
1095     frameLoadRequest.resourceRequest().setURL(makeURL(m_parentFrame->document()->baseURL(), url));
1096     frameLoadRequest.resourceRequest().setHTTPHeaderFields(WTFMove(headerFields));
1097     frameLoadRequest.resourceRequest().setHTTPBody(FormData::create(postData, postDataLength));
1098     frameLoadRequest.setFrameName(target);
1099
1100     return load(frameLoadRequest, sendNotification, notifyData);
1101 }
1102
1103 void PluginView::invalidateWindowlessPluginRect(const IntRect& rect)
1104 {
1105     if (!isVisible())
1106         return;
1107     
1108     if (!m_element->renderer())
1109         return;
1110     auto& renderer = downcast<RenderBox>(*m_element->renderer());
1111     
1112     IntRect dirtyRect = rect;
1113     dirtyRect.move(renderer.borderLeft() + renderer.paddingLeft(), renderer.borderTop() + renderer.paddingTop());
1114     renderer.repaintRectangle(dirtyRect);
1115 }
1116
1117 void PluginView::paintMissingPluginIcon(GraphicsContext& context, const IntRect& rect)
1118 {
1119     static RefPtr<Image> nullPluginImage;
1120     if (!nullPluginImage)
1121         nullPluginImage = Image::loadPlatformResource("nullPlugin");
1122
1123     IntRect imageRect(frameRect().x(), frameRect().y(), nullPluginImage->width(), nullPluginImage->height());
1124
1125     int xOffset = (frameRect().width() - imageRect.width()) / 2;
1126     int yOffset = (frameRect().height() - imageRect.height()) / 2;
1127
1128     imageRect.move(xOffset, yOffset);
1129
1130     if (!rect.intersects(imageRect))
1131         return;
1132
1133     context.save();
1134     context.clip(windowClipRect());
1135     context.drawImage(*nullPluginImage, imageRect.location());
1136     context.restore();
1137 }
1138
1139 static const char* MozillaUserAgent = "Mozilla/5.0 ("
1140         "Windows; U; Windows NT 5.1;"
1141         " en-US; rv:1.8.1) Gecko/20061010 Firefox/2.0";
1142
1143 static const char* const ChromeUserAgent = "Mozilla/5.0 ("
1144     "Windows; U; Windows NT 5.1;"
1145     " AppleWebKit/534.34 (KHTML, like Gecko) Chrome/19.0.1055.1 Safari/534.34";
1146
1147 const char* PluginView::userAgent()
1148 {
1149     if (m_plugin->quirks().contains(PluginQuirkWantsMozillaUserAgent))
1150         return MozillaUserAgent;
1151     else if (m_plugin->quirks().contains(PluginQuirkWantsChromeUserAgent))
1152         return ChromeUserAgent;
1153     if (m_userAgent.isNull())
1154         m_userAgent = m_parentFrame->loader().userAgent(m_url).utf8();
1155
1156     return m_userAgent.data();
1157 }
1158
1159 #if ENABLE(NETSCAPE_PLUGIN_API)
1160 const char* PluginView::userAgentStatic()
1161 {
1162     return MozillaUserAgent;
1163 }
1164 #endif
1165
1166
1167 void PluginView::lifeSupportTimerFired()
1168 {
1169     deref();
1170 }
1171
1172 void PluginView::keepAlive()
1173 {
1174     if (m_lifeSupportTimer.isActive())
1175         return;
1176
1177     ref();
1178     m_lifeSupportTimer.startOneShot(0);
1179 }
1180
1181 #if ENABLE(NETSCAPE_PLUGIN_API)
1182 void PluginView::keepAlive(NPP instance)
1183 {
1184     PluginView* view = instanceMap().get(instance);
1185     if (!view)
1186         return;
1187
1188     view->keepAlive();
1189 }
1190
1191 NPError PluginView::getValueStatic(NPNVariable variable, void* value)
1192 {
1193     LOG(Plugins, "PluginView::getValueStatic(%s)", prettyNameForNPNVariable(variable).data());
1194
1195     NPError result;
1196     if (platformGetValueStatic(variable, value, &result))
1197         return result;
1198
1199     return NPERR_GENERIC_ERROR;
1200 }
1201
1202 static Frame* getFrame(Frame* parentFrame, Element* element)
1203 {
1204     if (parentFrame)
1205         return parentFrame;
1206     
1207     return element->document().frame();
1208 }
1209
1210 NPError PluginView::getValue(NPNVariable variable, void* value)
1211 {
1212     LOG(Plugins, "PluginView::getValue(%s)", prettyNameForNPNVariable(variable).data());
1213
1214     NPError result;
1215     if (platformGetValue(variable, value, &result))
1216         return result;
1217
1218     if (platformGetValueStatic(variable, value, &result))
1219         return result;
1220
1221     switch (variable) {
1222     case NPNVWindowNPObject: {
1223         if (m_isJavaScriptPaused)
1224             return NPERR_GENERIC_ERROR;
1225
1226         NPObject* windowScriptObject = m_parentFrame->script().windowScriptNPObject();
1227
1228         // Return value is expected to be retained, as described here: <http://www.mozilla.org/projects/plugin/npruntime.html>
1229         if (windowScriptObject)
1230             _NPN_RetainObject(windowScriptObject);
1231
1232         void** v = (void**)value;
1233         *v = windowScriptObject;
1234
1235         return NPERR_NO_ERROR;
1236     }
1237
1238     case NPNVPluginElementNPObject: {
1239         if (m_isJavaScriptPaused)
1240             return NPERR_GENERIC_ERROR;
1241
1242         if (!m_elementNPObject) {
1243             Frame* frame = getFrame(parentFrame(), m_element);
1244             if (!frame)
1245                 return NPERR_GENERIC_ERROR;
1246
1247             JSC::JSObject* object = frame->script().jsObjectForPluginElement(m_element);
1248             if (!object)
1249                 m_elementNPObject = _NPN_CreateNoScriptObject();
1250             else
1251                 m_elementNPObject = _NPN_CreateScriptObject(0, object, frame->script().bindingRootObject());
1252         }
1253
1254         // Return value is expected to be retained, as described here: <http://www.mozilla.org/projects/plugins/npruntime.html#browseraccess>
1255         if (m_elementNPObject)
1256             _NPN_RetainObject(m_elementNPObject);
1257
1258         *(void **)value = m_elementNPObject;
1259         return NPERR_NO_ERROR;
1260     }
1261
1262     case NPNVprivateModeBool: {
1263         Page* page = m_parentFrame->page();
1264         if (!page)
1265             return NPERR_GENERIC_ERROR;
1266         *((NPBool*)value) = page->usesEphemeralSession();
1267         return NPERR_NO_ERROR;
1268     }
1269
1270     default:
1271         return NPERR_GENERIC_ERROR;
1272     }
1273 }
1274
1275 NPError PluginView::getValueForURL(NPNURLVariable variable, const char* url, char** value, uint32_t* len)
1276 {
1277     LOG(Plugins, "PluginView::getValueForURL(%s)", prettyNameForNPNURLVariable(variable).data());
1278
1279     NPError result = NPERR_NO_ERROR;
1280
1281     switch (variable) {
1282     case NPNURLVCookie: {
1283         URL u(m_parentFrame->document()->baseURL(), url);
1284         if (u.isValid()) {
1285             Frame* frame = getFrame(parentFrame(), m_element);
1286             if (frame && frame->document()) {
1287                 const CString cookieStr = cookies(*frame->document(), u).utf8();
1288                 if (!cookieStr.isNull()) {
1289                     const int size = cookieStr.length();
1290                     *value = static_cast<char*>(NPN_MemAlloc(size+1));
1291                     if (*value) {
1292                         memset(*value, 0, size+1);
1293                         memcpy(*value, cookieStr.data(), size+1);
1294                         if (len)
1295                             *len = size;
1296                     } else
1297                         result = NPERR_OUT_OF_MEMORY_ERROR;
1298                 }
1299             }
1300         } else
1301             result = NPERR_INVALID_URL;
1302         break;
1303     }
1304     case NPNURLVProxy: {
1305         URL u(m_parentFrame->document()->baseURL(), url);
1306         if (u.isValid()) {
1307             Frame* frame = getFrame(parentFrame(), m_element);
1308             const FrameLoader* frameLoader = frame ? &frame->loader() : 0;
1309             const NetworkingContext* context = frameLoader ? frameLoader->networkingContext() : 0;
1310             const CString proxyStr = toString(proxyServersForURL(u, context)).utf8();
1311             if (!proxyStr.isNull()) {
1312                 const int size = proxyStr.length();
1313                 *value = static_cast<char*>(NPN_MemAlloc(size+1));
1314                 if (*value) {
1315                     memset(*value, 0, size+1);
1316                     memcpy(*value, proxyStr.data(), size+1);
1317                     if (len)
1318                         *len = size;
1319                 } else
1320                     result = NPERR_OUT_OF_MEMORY_ERROR;
1321             }
1322         } else
1323             result = NPERR_INVALID_URL;
1324         break;
1325     }
1326     default:
1327         result = NPERR_GENERIC_ERROR;
1328         LOG(Plugins, "PluginView::getValueForURL: %s", prettyNameForNPNURLVariable(variable).data());
1329         break;
1330     }
1331
1332     return result;
1333 }
1334
1335
1336 NPError PluginView::setValueForURL(NPNURLVariable variable, const char* url, const char* value, uint32_t len)
1337 {
1338     LOG(Plugins, "PluginView::setValueForURL(%s)", prettyNameForNPNURLVariable(variable).data());
1339
1340     NPError result = NPERR_NO_ERROR;
1341
1342     switch (variable) {
1343     case NPNURLVCookie: {
1344         URL u(m_parentFrame->document()->baseURL(), url);
1345         if (u.isValid()) {
1346             const String cookieStr = String::fromUTF8(value, len);
1347             Frame* frame = getFrame(parentFrame(), m_element);
1348             if (frame && frame->document() && !cookieStr.isEmpty())
1349                 setCookies(*frame->document(), u, cookieStr);
1350         } else
1351             result = NPERR_INVALID_URL;
1352         break;
1353     }
1354     case NPNURLVProxy:
1355         LOG(Plugins, "PluginView::setValueForURL(%s): Plugins are NOT allowed to set proxy information.", prettyNameForNPNURLVariable(variable).data());
1356         result = NPERR_GENERIC_ERROR;
1357         break;
1358     default:
1359         LOG(Plugins, "PluginView::setValueForURL: %s", prettyNameForNPNURLVariable(variable).data());
1360         result = NPERR_GENERIC_ERROR;
1361         break;
1362     }
1363
1364     return result;
1365 }
1366
1367 NPError PluginView::getAuthenticationInfo(const char* protocol, const char* host, int32_t port, const char* /* scheme */, const char* /* realm */, char**  /* username */, uint32_t* /* ulen */, char** /* password */, uint32_t* /* plen */)
1368 {
1369 #if LOG_DISABLED
1370     UNUSED_PARAM(protocol);
1371     UNUSED_PARAM(host);
1372     UNUSED_PARAM(port);
1373 #endif
1374     LOG(Plugins, "PluginView::getAuthenticationInfo: protocol=%s, host=%s, port=%d", protocol, host, port);
1375     notImplemented();
1376     return NPERR_GENERIC_ERROR;
1377 }
1378 #endif
1379
1380 void PluginView::privateBrowsingStateChanged(bool privateBrowsingEnabled)
1381 {
1382     NPP_SetValueProcPtr setValue = m_plugin->pluginFuncs()->setvalue;
1383     if (!setValue)
1384         return;
1385
1386     PluginView::setCurrentPluginView(this);
1387     JSC::JSLock::DropAllLocks dropAllLocks(commonVM());
1388     setCallingPlugin(true);
1389     NPBool value = privateBrowsingEnabled;
1390     setValue(m_instance, NPNVprivateModeBool, &value);
1391     setCallingPlugin(false);
1392     PluginView::setCurrentPluginView(0);
1393 }
1394
1395 } // namespace WebCore
1396
1397 #endif // ENABLE(NETSCAPE_PLUGIN_API)