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