1/*
2 * Copyright (C) 2010-2018 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "NetscapeBrowserFuncs.h"
28
29#if ENABLE(NETSCAPE_PLUGIN_API)
30
31#include "NPRuntimeUtilities.h"
32#include "NetscapePlugin.h"
33#include "PluginController.h"
34#include <WebCore/HTTPHeaderMap.h>
35#include <WebCore/HTTPHeaderNames.h>
36#include <WebCore/IdentifierRep.h>
37#include <WebCore/NotImplemented.h>
38#include <WebCore/ProtectionSpace.h>
39#include <WebCore/SharedBuffer.h>
40#include <memory>
41#include <utility>
42#include <wtf/text/StringBuilder.h>
43
44#if PLATFORM(COCOA)
45#include <wtf/MachSendRight.h>
46#endif
47
48#if PLATFORM(X11)
49#include <WebCore/PlatformDisplayX11.h>
50#endif
51
52namespace WebKit {
53using namespace WebCore;
54
55// Helper class for delaying destruction of a plug-in.
56class PluginDestructionProtector {
57public:
58 explicit PluginDestructionProtector(NetscapePlugin* plugin)
59 {
60 if (plugin)
61 m_protector = std::make_unique<PluginController::PluginDestructionProtector>(static_cast<Plugin*>(plugin)->controller());
62 }
63
64private:
65 std::unique_ptr<PluginController::PluginDestructionProtector> m_protector;
66};
67
68static bool startsWithBlankLine(const char* bytes, unsigned length)
69{
70 return length > 0 && bytes[0] == '\n';
71}
72
73static int locationAfterFirstBlankLine(const char* bytes, unsigned length)
74{
75 for (unsigned i = 0; i < length - 4; i++) {
76 // Support for Acrobat. It sends "\n\n".
77 if (bytes[i] == '\n' && bytes[i + 1] == '\n')
78 return i + 2;
79
80 // Returns the position after 2 CRLF's or 1 CRLF if it is the first line.
81 if (bytes[i] == '\r' && bytes[i + 1] == '\n') {
82 i += 2;
83 if (i == 2)
84 return i;
85
86 if (bytes[i] == '\n') {
87 // Support for Director. It sends "\r\n\n" (3880387).
88 return i + 1;
89 }
90
91 if (bytes[i] == '\r' && bytes[i + 1] == '\n') {
92 // Support for Flash. It sends "\r\n\r\n" (3758113).
93 return i + 2;
94 }
95 }
96 }
97
98 return -1;
99}
100
101static const char* findEndOfLine(const char* bytes, unsigned length)
102{
103 // According to the HTTP specification EOL is defined as
104 // a CRLF pair. Unfortunately, some servers will use LF
105 // instead. Worse yet, some servers will use a combination
106 // of both (e.g. <header>CRLFLF<body>), so findEOL needs
107 // to be more forgiving. It will now accept CRLF, LF or
108 // CR.
109 //
110 // It returns 0 if EOLF is not found or it will return
111 // a pointer to the first terminating character.
112 for (unsigned i = 0; i < length; i++) {
113 if (bytes[i] == '\n')
114 return bytes + i;
115 if (bytes[i] == '\r') {
116 // Check to see if spanning buffer bounds
117 // (CRLF is across reads). If so, wait for
118 // next read.
119 if (i + 1 == length)
120 break;
121
122 return bytes + i;
123 }
124 }
125
126 return 0;
127}
128
129static String capitalizeRFC822HeaderFieldName(const String& name)
130{
131 bool capitalizeCharacter = true;
132 StringBuilder result;
133 for (unsigned i = 0; i < name.length(); i++) {
134 result.append(capitalizeCharacter ? toASCIIUpper(name[i]) : toASCIILower(name[i]));
135 if (name[i] == '-')
136 capitalizeCharacter = true;
137 else
138 capitalizeCharacter = false;
139 }
140 return result.toString();
141}
142
143static HTTPHeaderMap parseRFC822HeaderFields(const char* bytes, unsigned length)
144{
145 String lastHeaderKey;
146 HTTPHeaderMap headerFields;
147
148 // Loop over lines until we're past the header, or we can't find any more end-of-lines
149 while (const char* endOfLine = findEndOfLine(bytes, length)) {
150 const char* line = bytes;
151 int lineLength = endOfLine - bytes;
152
153 // Move bytes to the character after the terminator as returned by findEndOfLine.
154 bytes = endOfLine + 1;
155 if ((*endOfLine == '\r') && (*bytes == '\n'))
156 bytes++; // Safe since findEndOfLine won't return a spanning CRLF.
157
158 length -= (bytes - line);
159 if (!lineLength) {
160 // Blank line; we're at the end of the header
161 break;
162 }
163
164 if (*line == ' ' || *line == '\t') {
165 // Continuation of the previous header
166 if (lastHeaderKey.isNull()) {
167 // malformed header; ignore it and continue
168 continue;
169 }
170
171 // Merge the continuation of the previous header
172 String currentValue = headerFields.get(lastHeaderKey);
173 String newValue(line, lineLength);
174
175 headerFields.set(lastHeaderKey, currentValue + newValue);
176 } else {
177 // Brand new header
178 const char* colon = line;
179 while (*colon != ':' && colon != endOfLine)
180 colon++;
181
182 if (colon == endOfLine) {
183 // malformed header; ignore it and continue
184 continue;
185 }
186
187 lastHeaderKey = capitalizeRFC822HeaderFieldName(String(line, colon - line));
188 String value;
189
190 for (colon++; colon != endOfLine; colon++) {
191 if (*colon != ' ' && *colon != '\t')
192 break;
193 }
194 if (colon == endOfLine)
195 value = emptyString();
196 else
197 value = String(colon, endOfLine - colon);
198
199 String oldValue = headerFields.get(lastHeaderKey);
200 if (!oldValue.isNull())
201 value = oldValue + ", " + value;
202
203 headerFields.set(lastHeaderKey, value);
204 }
205 }
206
207 return headerFields;
208}
209
210static NPError parsePostBuffer(bool isFile, const char *buffer, uint32_t length, bool parseHeaders, HTTPHeaderMap& headerFields, Vector<uint8_t>& bodyData)
211{
212 RefPtr<SharedBuffer> fileContents;
213 const char* postBuffer = 0;
214 uint32_t postBufferSize = 0;
215
216 if (isFile) {
217 fileContents = SharedBuffer::createWithContentsOfFile(String::fromUTF8(buffer));
218 if (!fileContents)
219 return NPERR_FILE_NOT_FOUND;
220
221 postBuffer = fileContents->data();
222 postBufferSize = fileContents->size();
223
224 // FIXME: The NPAPI spec states that the file should be deleted here.
225 } else {
226 postBuffer = buffer;
227 postBufferSize = length;
228 }
229
230 if (parseHeaders) {
231 if (startsWithBlankLine(postBuffer, postBufferSize)) {
232 postBuffer++;
233 postBufferSize--;
234 } else {
235 int location = locationAfterFirstBlankLine(postBuffer, postBufferSize);
236 if (location != -1) {
237 // If the blank line is somewhere in the middle of the buffer, everything before is the header
238 headerFields = parseRFC822HeaderFields(postBuffer, location);
239 unsigned dataLength = postBufferSize - location;
240
241 // Sometimes plugins like to set Content-Length themselves when they post,
242 // but WebFoundation does not like that. So we will remove the header
243 // and instead truncate the data to the requested length.
244 String contentLength = headerFields.get(HTTPHeaderName::ContentLength);
245
246 if (!contentLength.isNull())
247 dataLength = std::min(contentLength.toInt(), (int)dataLength);
248 headerFields.remove(HTTPHeaderName::ContentLength);
249
250 postBuffer += location;
251 postBufferSize = dataLength;
252 }
253 }
254 }
255
256 ASSERT(bodyData.isEmpty());
257 bodyData.append(postBuffer, postBufferSize);
258
259 return NPERR_NO_ERROR;
260}
261
262static String makeURLString(const char* url)
263{
264 String urlString(url);
265
266 // Strip return characters.
267 urlString.replaceWithLiteral('\r', "");
268 urlString.replaceWithLiteral('\n', "");
269
270 return urlString;
271}
272
273static NPError NPN_GetURL(NPP npp, const char* url, const char* target)
274{
275 if (!url)
276 return NPERR_GENERIC_ERROR;
277
278 RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
279 plugin->loadURL("GET", makeURLString(url), target, HTTPHeaderMap(), Vector<uint8_t>(), false, 0);
280
281 return NPERR_GENERIC_ERROR;
282}
283
284static NPError NPN_PostURL(NPP npp, const char* url, const char* target, uint32_t len, const char* buf, NPBool file)
285{
286 HTTPHeaderMap headerFields;
287 Vector<uint8_t> postData;
288
289 // NPN_PostURL only allows headers if the post buffer points to a file.
290 bool parseHeaders = file;
291
292 NPError error = parsePostBuffer(file, buf, len, parseHeaders, headerFields, postData);
293 if (error != NPERR_NO_ERROR)
294 return error;
295
296 RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
297 plugin->loadURL("POST", makeURLString(url), target, WTFMove(headerFields), postData, false, 0);
298 return NPERR_NO_ERROR;
299}
300
301static NPError NPN_RequestRead(NPStream*, NPByteRange*)
302{
303 notImplemented();
304 return NPERR_GENERIC_ERROR;
305}
306
307static NPError NPN_NewStream(NPP, NPMIMEType, const char*, NPStream**)
308{
309 notImplemented();
310 return NPERR_GENERIC_ERROR;
311}
312
313static int32_t NPN_Write(NPP, NPStream*, int32_t, void*)
314{
315 notImplemented();
316 return -1;
317}
318
319static NPError NPN_DestroyStream(NPP npp, NPStream* stream, NPReason reason)
320{
321 RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
322
323 return plugin->destroyStream(stream, reason);
324}
325
326static void NPN_Status(NPP npp, const char* message)
327{
328 String statusbarText;
329 if (!message)
330 statusbarText = emptyString();
331 else
332 statusbarText = String::fromUTF8WithLatin1Fallback(message, strlen(message));
333
334 RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
335 plugin->setStatusbarText(statusbarText);
336}
337
338static const char* NPN_UserAgent(NPP npp)
339{
340 return NetscapePlugin::userAgent(npp);
341}
342
343static void* NPN_MemAlloc(uint32_t size)
344{
345 return npnMemAlloc(size);
346}
347
348static void NPN_MemFree(void* ptr)
349{
350 npnMemFree(ptr);
351}
352
353static uint32_t NPN_MemFlush(uint32_t)
354{
355 return 0;
356}
357
358static void NPN_ReloadPlugins(NPBool)
359{
360 notImplemented();
361}
362
363static JRIEnv* NPN_GetJavaEnv(void)
364{
365 notImplemented();
366 return 0;
367}
368
369static jref NPN_GetJavaPeer(NPP)
370{
371 notImplemented();
372 return 0;
373}
374
375static NPError NPN_GetURLNotify(NPP npp, const char* url, const char* target, void* notifyData)
376{
377 if (!url)
378 return NPERR_GENERIC_ERROR;
379
380 RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
381 plugin->loadURL("GET", makeURLString(url), target, HTTPHeaderMap(), Vector<uint8_t>(), true, notifyData);
382
383 return NPERR_NO_ERROR;
384}
385
386static NPError NPN_PostURLNotify(NPP npp, const char* url, const char* target, uint32_t len, const char* buf, NPBool file, void* notifyData)
387{
388 HTTPHeaderMap headerFields;
389 Vector<uint8_t> postData;
390 NPError error = parsePostBuffer(file, buf, len, true, headerFields, postData);
391 if (error != NPERR_NO_ERROR)
392 return error;
393
394 RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
395 plugin->loadURL("POST", makeURLString(url), target, headerFields, postData, true, notifyData);
396 return NPERR_NO_ERROR;
397}
398
399#if PLATFORM(COCOA)
400// Whether the browser supports compositing of Core Animation plug-ins.
401static const unsigned WKNVSupportsCompositingCoreAnimationPluginsBool = 74656;
402
403// Whether the browser expects a non-retained Core Animation layer.
404static const unsigned WKNVExpectsNonretainedLayer = 74657;
405
406// 74658 and 74659 are no longer implemented.
407
408#endif
409
410static NPError NPN_GetValue(NPP npp, NPNVariable variable, void *value)
411{
412 switch (static_cast<unsigned>(variable)) {
413 case NPNVWindowNPObject: {
414 RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
415 PluginDestructionProtector protector(plugin.get());
416
417 NPObject* windowNPObject = plugin->windowScriptNPObject();
418 if (!windowNPObject)
419 return NPERR_GENERIC_ERROR;
420
421 *(NPObject**)value = windowNPObject;
422 break;
423 }
424 case NPNVPluginElementNPObject: {
425 RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
426 PluginDestructionProtector protector(plugin.get());
427
428 NPObject* pluginElementNPObject = plugin->pluginElementNPObject();
429 *(NPObject**)value = pluginElementNPObject;
430 break;
431 }
432 case NPNVprivateModeBool: {
433 RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
434
435 *(NPBool*)value = plugin->isPrivateBrowsingEnabled();
436 break;
437 }
438
439 case NPNVmuteAudioBool: {
440 RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
441 *(NPBool*)value = plugin->isMuted();
442 break;
443 }
444#if PLATFORM(COCOA)
445 case NPNVsupportsCoreGraphicsBool:
446 // Always claim to support the Core Graphics drawing model.
447 *(NPBool*)value = true;
448 break;
449
450 case WKNVSupportsCompositingCoreAnimationPluginsBool:
451 case NPNVsupportsCoreAnimationBool: {
452 RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
453
454 *(NPBool*)value = plugin->isAcceleratedCompositingEnabled();
455 break;
456 }
457 case NPNVcontentsScaleFactor: {
458 RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
459
460 *(double*)value = plugin->contentsScaleFactor();
461 break;
462 }
463 case NPNVsupportsCocoaBool:
464 // Always claim to support the Cocoa event model.
465 *(NPBool*)value = true;
466 break;
467
468 case NPNVsupportsUpdatedCocoaTextInputBool: {
469 // The plug-in is asking whether we support the updated Cocoa text input model.
470 // If we haven't yet delivered a key down event to the plug-in, we can opt into the updated
471 // model and say that we support it. Otherwise, we'll just fall back and say that we don't support it.
472 RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
473
474 bool supportsUpdatedTextInput = !plugin->hasHandledAKeyDownEvent();
475 if (supportsUpdatedTextInput)
476 plugin->setPluginWantsLegacyCocoaTextInput(false);
477
478 *reinterpret_cast<NPBool*>(value) = supportsUpdatedTextInput;
479 break;
480 }
481
482 case WKNVCALayerRenderServerPort: {
483 RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
484
485 *(mach_port_t*)value = plugin->compositingRenderServerPort().sendRight();
486 break;
487 }
488
489 case WKNVExpectsNonretainedLayer: {
490 RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
491
492 // Asking for this will make us expect a non-retained layer from the plug-in.
493 plugin->setPluginReturnsNonretainedLayer(true);
494 *(NPBool*)value = true;
495 break;
496 }
497#elif PLATFORM(X11)
498 case NPNVxDisplay: {
499 if (!npp)
500 return NPERR_GENERIC_ERROR;
501 auto& display = PlatformDisplay::sharedDisplay();
502 if (display.type() != PlatformDisplay::Type::X11)
503 return NPERR_GENERIC_ERROR;
504 *reinterpret_cast<Display**>(value) = downcast<PlatformDisplayX11>(display).native();
505 break;
506 }
507 case NPNVSupportsXEmbedBool:
508 *static_cast<NPBool*>(value) = PlatformDisplay::sharedDisplay().type() == PlatformDisplay::Type::X11;
509 break;
510 case NPNVSupportsWindowless:
511 *static_cast<NPBool*>(value) = true;
512 break;
513
514 case NPNVToolkit: {
515 // Gtk based plugins need to be assured about the toolkit version.
516 const uint32_t expectedGtkToolKitVersion = 2;
517 *reinterpret_cast<uint32_t*>(value) = expectedGtkToolKitVersion;
518 break;
519 }
520
521 // TODO: implement NPNVnetscapeWindow once we want to support windowed plugins.
522#endif
523 default:
524 notImplemented();
525 return NPERR_GENERIC_ERROR;
526 }
527
528 return NPERR_NO_ERROR;
529}
530
531static NPError NPN_SetValue(NPP npp, NPPVariable variable, void *value)
532{
533 switch (variable) {
534#if PLATFORM(COCOA)
535 case NPPVpluginDrawingModel: {
536 RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
537
538 NPDrawingModel drawingModel = static_cast<NPDrawingModel>(reinterpret_cast<uintptr_t>(value));
539 return plugin->setDrawingModel(drawingModel);
540 }
541
542 case NPPVpluginEventModel: {
543 RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
544
545 NPEventModel eventModel = static_cast<NPEventModel>(reinterpret_cast<uintptr_t>(value));
546 return plugin->setEventModel(eventModel);
547 }
548#endif
549
550 case NPPVpluginWindowBool: {
551 RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
552 plugin->setIsWindowed(value);
553 return NPERR_NO_ERROR;
554 }
555
556 case NPPVpluginTransparentBool: {
557 RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
558 plugin->setIsTransparent(value);
559 return NPERR_NO_ERROR;
560 }
561
562 case NPPVpluginIsPlayingAudio: {
563 RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
564 plugin->setIsPlayingAudio(value);
565 return NPERR_NO_ERROR;
566 }
567
568 default:
569 notImplemented();
570 return NPERR_GENERIC_ERROR;
571 }
572}
573
574static void NPN_InvalidateRect(NPP npp, NPRect* invalidRect)
575{
576#if PLUGIN_ARCHITECTURE(UNIX)
577 // NSPluginWrapper, a plugin wrapper binary that allows running 32-bit plugins
578 // on 64-bit architectures typically used in X11, will sometimes give us a null NPP here.
579 if (!npp)
580 return;
581#endif
582 RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
583 plugin->invalidate(invalidRect);
584}
585
586static void NPN_InvalidateRegion(NPP npp, NPRegion)
587{
588 // FIXME: We could at least figure out the bounding rectangle of the invalid region.
589 RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
590 plugin->invalidate(0);
591}
592
593static void NPN_ForceRedraw(NPP)
594{
595 notImplemented();
596}
597
598static NPIdentifier NPN_GetStringIdentifier(const NPUTF8 *name)
599{
600 return static_cast<NPIdentifier>(IdentifierRep::get(name));
601}
602
603static void NPN_GetStringIdentifiers(const NPUTF8 **names, int32_t nameCount, NPIdentifier *identifiers)
604{
605 ASSERT(names);
606 ASSERT(identifiers);
607
608 if (!names || !identifiers)
609 return;
610
611 for (int32_t i = 0; i < nameCount; ++i)
612 identifiers[i] = NPN_GetStringIdentifier(names[i]);
613}
614
615static NPIdentifier NPN_GetIntIdentifier(int32_t intid)
616{
617 return static_cast<NPIdentifier>(IdentifierRep::get(intid));
618}
619
620static bool NPN_IdentifierIsString(NPIdentifier identifier)
621{
622 return static_cast<IdentifierRep*>(identifier)->isString();
623}
624
625static NPUTF8 *NPN_UTF8FromIdentifier(NPIdentifier identifier)
626{
627 const char* string = static_cast<IdentifierRep*>(identifier)->string();
628 if (!string)
629 return 0;
630
631 uint32_t stringLength = strlen(string);
632 char* utf8String = npnMemNewArray<char>(stringLength + 1);
633 memcpy(utf8String, string, stringLength);
634 utf8String[stringLength] = '\0';
635
636 return utf8String;
637}
638
639static int32_t NPN_IntFromIdentifier(NPIdentifier identifier)
640{
641 return static_cast<IdentifierRep*>(identifier)->number();
642}
643
644static NPObject* NPN_CreateObject(NPP npp, NPClass *npClass)
645{
646 return createNPObject(npp, npClass);
647}
648
649static NPObject *NPN_RetainObject(NPObject *npObject)
650{
651 retainNPObject(npObject);
652 return npObject;
653}
654
655static void NPN_ReleaseObject(NPObject *npObject)
656{
657 releaseNPObject(npObject);
658}
659
660static bool NPN_Invoke(NPP npp, NPObject *npObject, NPIdentifier methodName, const NPVariant* arguments, uint32_t argumentCount, NPVariant* result)
661{
662 RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
663 PluginDestructionProtector protector(plugin.get());
664
665 if (npObject->_class->invoke)
666 return npObject->_class->invoke(npObject, methodName, arguments, argumentCount, result);
667
668 return false;
669}
670
671static bool NPN_InvokeDefault(NPP npp, NPObject *npObject, const NPVariant* arguments, uint32_t argumentCount, NPVariant* result)
672{
673 RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
674 PluginDestructionProtector protector(plugin.get());
675
676 if (npObject->_class->invokeDefault)
677 return npObject->_class->invokeDefault(npObject, arguments, argumentCount, result);
678
679 return false;
680}
681
682static bool NPN_Evaluate(NPP npp, NPObject *npObject, NPString *script, NPVariant* result)
683{
684 RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
685 PluginDestructionProtector protector(plugin.get());
686
687 String scriptString = String::fromUTF8WithLatin1Fallback(script->UTF8Characters, script->UTF8Length);
688
689 return plugin->evaluate(npObject, scriptString, result);
690}
691
692static bool NPN_GetProperty(NPP npp, NPObject* npObject, NPIdentifier propertyName, NPVariant* result)
693{
694 RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
695 PluginDestructionProtector protector(plugin.get());
696
697 if (npObject->_class->getProperty)
698 return npObject->_class->getProperty(npObject, propertyName, result);
699
700 return false;
701}
702
703static bool NPN_SetProperty(NPP npp, NPObject* npObject, NPIdentifier propertyName, const NPVariant* value)
704{
705 RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
706 PluginDestructionProtector protector(plugin.get());
707
708 if (npObject->_class->setProperty)
709 return npObject->_class->setProperty(npObject, propertyName, value);
710
711 return false;
712}
713
714static bool NPN_RemoveProperty(NPP npp, NPObject* npObject, NPIdentifier propertyName)
715{
716 RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
717 PluginDestructionProtector protector(plugin.get());
718
719 if (npObject->_class->removeProperty)
720 return npObject->_class->removeProperty(npObject, propertyName);
721
722 return false;
723}
724
725static bool NPN_HasProperty(NPP npp, NPObject* npObject, NPIdentifier propertyName)
726{
727 RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
728 PluginDestructionProtector protector(plugin.get());
729
730 if (npObject->_class->hasProperty)
731 return npObject->_class->hasProperty(npObject, propertyName);
732
733 return false;
734}
735
736static bool NPN_HasMethod(NPP npp, NPObject* npObject, NPIdentifier methodName)
737{
738 RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
739 PluginDestructionProtector protector(plugin.get());
740
741 if (npObject->_class->hasMethod)
742 return npObject->_class->hasMethod(npObject, methodName);
743
744 return false;
745}
746
747static void NPN_ReleaseVariantValue(NPVariant* variant)
748{
749 releaseNPVariantValue(variant);
750}
751
752static void NPN_SetException(NPObject*, const NPUTF8* message)
753{
754 NetscapePlugin::setException(message);
755}
756
757static void NPN_PushPopupsEnabledState(NPP npp, NPBool enabled)
758{
759 RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
760 plugin->pushPopupsEnabledState(enabled);
761}
762
763static void NPN_PopPopupsEnabledState(NPP npp)
764{
765 RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
766 plugin->popPopupsEnabledState();
767}
768
769static bool NPN_Enumerate(NPP npp, NPObject* npObject, NPIdentifier** identifiers, uint32_t* identifierCount)
770{
771 RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
772 PluginDestructionProtector protector(plugin.get());
773
774 if (NP_CLASS_STRUCT_VERSION_HAS_ENUM(npObject->_class) && npObject->_class->enumerate)
775 return npObject->_class->enumerate(npObject, identifiers, identifierCount);
776
777 return false;
778}
779
780static void NPN_PluginThreadAsyncCall(NPP npp, void (*function)(void*), void* userData)
781{
782 RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
783
784 plugin->pluginThreadAsyncCall(function, userData);
785}
786
787static bool NPN_Construct(NPP npp, NPObject* npObject, const NPVariant* arguments, uint32_t argumentCount, NPVariant* result)
788{
789 RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
790 PluginDestructionProtector protector(plugin.get());
791
792 if (NP_CLASS_STRUCT_VERSION_HAS_CTOR(npObject->_class) && npObject->_class->construct)
793 return npObject->_class->construct(npObject, arguments, argumentCount, result);
794
795 return false;
796}
797
798static NPError copyCString(const CString& string, char** value, uint32_t* len)
799{
800 ASSERT(!string.isNull());
801 ASSERT(value);
802 ASSERT(len);
803
804 *value = npnMemNewArray<char>(string.length());
805 if (!*value)
806 return NPERR_GENERIC_ERROR;
807
808 memcpy(*value, string.data(), string.length());
809 *len = string.length();
810 return NPERR_NO_ERROR;
811}
812
813static NPError NPN_GetValueForURL(NPP npp, NPNURLVariable variable, const char* url, char** value, uint32_t* len)
814{
815 if (!value || !len)
816 return NPERR_GENERIC_ERROR;
817
818 switch (variable) {
819 case NPNURLVCookie: {
820 RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
821 PluginDestructionProtector protector(plugin.get());
822
823 String cookies = plugin->cookiesForURL(makeURLString(url));
824 if (cookies.isNull())
825 return NPERR_GENERIC_ERROR;
826
827 return copyCString(cookies.utf8(), value, len);
828 }
829
830 case NPNURLVProxy: {
831 RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
832 PluginDestructionProtector protector(plugin.get());
833
834 String proxies = plugin->proxiesForURL(makeURLString(url));
835 if (proxies.isNull())
836 return NPERR_GENERIC_ERROR;
837
838 return copyCString(proxies.utf8(), value, len);
839 }
840 default:
841 notImplemented();
842 return NPERR_GENERIC_ERROR;
843 }
844}
845
846static NPError NPN_SetValueForURL(NPP npp, NPNURLVariable variable, const char* url, const char* value, uint32_t len)
847{
848 switch (variable) {
849 case NPNURLVCookie: {
850 RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
851 PluginDestructionProtector protector(plugin.get());
852
853 plugin->setCookiesForURL(makeURLString(url), String(value, len));
854 return NPERR_NO_ERROR;
855 }
856
857 case NPNURLVProxy:
858 // Can't set the proxy for a URL.
859 return NPERR_GENERIC_ERROR;
860
861 default:
862 notImplemented();
863 return NPERR_GENERIC_ERROR;
864 }
865}
866
867static bool initializeProtectionSpace(const char* protocol, const char* host, int port, const char* scheme, const char* realm, ProtectionSpace& protectionSpace)
868{
869 ProtectionSpaceServerType serverType;
870 if (equalLettersIgnoringASCIICase(protocol, "http"))
871 serverType = ProtectionSpaceServerHTTP;
872 else if (equalLettersIgnoringASCIICase(protocol, "https"))
873 serverType = ProtectionSpaceServerHTTPS;
874 else {
875 // We only care about http and https.
876 return false;
877 }
878
879 ProtectionSpaceAuthenticationScheme authenticationScheme = ProtectionSpaceAuthenticationSchemeDefault;
880 if (serverType == ProtectionSpaceServerHTTP) {
881 if (equalLettersIgnoringASCIICase(scheme, "basic"))
882 authenticationScheme = ProtectionSpaceAuthenticationSchemeHTTPBasic;
883 else if (equalLettersIgnoringASCIICase(scheme, "digest"))
884 authenticationScheme = ProtectionSpaceAuthenticationSchemeHTTPDigest;
885 }
886
887 protectionSpace = ProtectionSpace(host, port, serverType, realm, authenticationScheme);
888 return true;
889}
890
891static NPError NPN_GetAuthenticationInfo(NPP npp, const char* protocol, const char* host, int32_t port, const char* scheme,
892 const char* realm, char** username, uint32_t* usernameLength, char** password, uint32_t* passwordLength)
893{
894 if (!protocol || !host || !scheme || !realm || !username || !usernameLength || !password || !passwordLength)
895 return NPERR_GENERIC_ERROR;
896
897 ProtectionSpace protectionSpace;
898 if (!initializeProtectionSpace(protocol, host, port, scheme, realm, protectionSpace))
899 return NPERR_GENERIC_ERROR;
900
901 RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
902 String usernameString;
903 String passwordString;
904 if (!plugin->getAuthenticationInfo(protectionSpace, usernameString, passwordString))
905 return NPERR_GENERIC_ERROR;
906
907 NPError result = copyCString(usernameString.utf8(), username, usernameLength);
908 if (result != NPERR_NO_ERROR)
909 return result;
910
911 result = copyCString(passwordString.utf8(), password, passwordLength);
912 if (result != NPERR_NO_ERROR) {
913 npnMemFree(*username);
914 return result;
915 }
916
917 return NPERR_NO_ERROR;
918}
919
920static uint32_t NPN_ScheduleTimer(NPP npp, uint32_t interval, NPBool repeat, void (*timerFunc)(NPP npp, uint32_t timerID))
921{
922 RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
923
924 return plugin->scheduleTimer(interval, repeat, timerFunc);
925}
926
927static void NPN_UnscheduleTimer(NPP npp, uint32_t timerID)
928{
929 RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
930
931 plugin->unscheduleTimer(timerID);
932}
933
934#if PLATFORM(COCOA)
935static NPError NPN_PopUpContextMenu(NPP npp, NPMenu* menu)
936{
937 RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
938
939 return plugin->popUpContextMenu(menu);
940}
941
942static NPBool NPN_ConvertPoint(NPP npp, double sourceX, double sourceY, NPCoordinateSpace sourceSpace, double* destX, double* destY, NPCoordinateSpace destSpace)
943{
944 RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
945
946 double destinationX;
947 double destinationY;
948
949 bool returnValue = plugin->convertPoint(sourceX, sourceY, sourceSpace, destinationX, destinationY, destSpace);
950
951 if (destX)
952 *destX = destinationX;
953 if (destY)
954 *destY = destinationY;
955
956 return returnValue;
957}
958#endif
959
960static void NPN_URLRedirectResponse(NPP npp, void* notifyData, NPBool allow)
961{
962 RefPtr<NetscapePlugin> plugin = NetscapePlugin::fromNPP(npp);
963
964 plugin->urlRedirectResponse(notifyData, allow);
965}
966
967static void initializeBrowserFuncs(NPNetscapeFuncs &netscapeFuncs)
968{
969 netscapeFuncs.size = sizeof(NPNetscapeFuncs);
970 netscapeFuncs.version = (NP_VERSION_MAJOR << 8) | NP_VERSION_MINOR;
971
972 netscapeFuncs.geturl = NPN_GetURL;
973 netscapeFuncs.posturl = NPN_PostURL;
974 netscapeFuncs.requestread = NPN_RequestRead;
975 netscapeFuncs.newstream = NPN_NewStream;
976 netscapeFuncs.write = NPN_Write;
977 netscapeFuncs.destroystream = NPN_DestroyStream;
978 netscapeFuncs.status = NPN_Status;
979 netscapeFuncs.uagent = NPN_UserAgent;
980 netscapeFuncs.memalloc = NPN_MemAlloc;
981 netscapeFuncs.memfree = NPN_MemFree;
982 netscapeFuncs.memflush = NPN_MemFlush;
983 netscapeFuncs.reloadplugins = NPN_ReloadPlugins;
984 netscapeFuncs.getJavaEnv = NPN_GetJavaEnv;
985 netscapeFuncs.getJavaPeer = NPN_GetJavaPeer;
986 netscapeFuncs.geturlnotify = NPN_GetURLNotify;
987 netscapeFuncs.posturlnotify = NPN_PostURLNotify;
988 netscapeFuncs.getvalue = NPN_GetValue;
989 netscapeFuncs.setvalue = NPN_SetValue;
990 netscapeFuncs.invalidaterect = NPN_InvalidateRect;
991 netscapeFuncs.invalidateregion = NPN_InvalidateRegion;
992 netscapeFuncs.forceredraw = NPN_ForceRedraw;
993
994 netscapeFuncs.getstringidentifier = NPN_GetStringIdentifier;
995 netscapeFuncs.getstringidentifiers = NPN_GetStringIdentifiers;
996 netscapeFuncs.getintidentifier = NPN_GetIntIdentifier;
997 netscapeFuncs.identifierisstring = NPN_IdentifierIsString;
998 netscapeFuncs.utf8fromidentifier = NPN_UTF8FromIdentifier;
999 netscapeFuncs.intfromidentifier = NPN_IntFromIdentifier;
1000 netscapeFuncs.createobject = NPN_CreateObject;
1001 netscapeFuncs.retainobject = NPN_RetainObject;
1002 netscapeFuncs.releaseobject = NPN_ReleaseObject;
1003 netscapeFuncs.invoke = NPN_Invoke;
1004 netscapeFuncs.invokeDefault = NPN_InvokeDefault;
1005 netscapeFuncs.evaluate = NPN_Evaluate;
1006 netscapeFuncs.getproperty = NPN_GetProperty;
1007 netscapeFuncs.setproperty = NPN_SetProperty;
1008 netscapeFuncs.removeproperty = NPN_RemoveProperty;
1009 netscapeFuncs.hasproperty = NPN_HasProperty;
1010 netscapeFuncs.hasmethod = NPN_HasMethod;
1011 netscapeFuncs.releasevariantvalue = NPN_ReleaseVariantValue;
1012 netscapeFuncs.setexception = NPN_SetException;
1013 netscapeFuncs.pushpopupsenabledstate = NPN_PushPopupsEnabledState;
1014 netscapeFuncs.poppopupsenabledstate = NPN_PopPopupsEnabledState;
1015 netscapeFuncs.enumerate = NPN_Enumerate;
1016 netscapeFuncs.pluginthreadasynccall = NPN_PluginThreadAsyncCall;
1017 netscapeFuncs.construct = NPN_Construct;
1018 netscapeFuncs.getvalueforurl = NPN_GetValueForURL;
1019 netscapeFuncs.setvalueforurl = NPN_SetValueForURL;
1020 netscapeFuncs.getauthenticationinfo = NPN_GetAuthenticationInfo;
1021 netscapeFuncs.scheduletimer = NPN_ScheduleTimer;
1022 netscapeFuncs.unscheduletimer = NPN_UnscheduleTimer;
1023#if PLATFORM(COCOA)
1024 netscapeFuncs.popupcontextmenu = NPN_PopUpContextMenu;
1025 netscapeFuncs.convertpoint = NPN_ConvertPoint;
1026#else
1027 netscapeFuncs.popupcontextmenu = 0;
1028 netscapeFuncs.convertpoint = 0;
1029#endif
1030 netscapeFuncs.urlredirectresponse = NPN_URLRedirectResponse;
1031}
1032
1033NPNetscapeFuncs* netscapeBrowserFuncs()
1034{
1035 static NPNetscapeFuncs netscapeFuncs;
1036 static bool initialized = false;
1037
1038 if (!initialized) {
1039 initializeBrowserFuncs(netscapeFuncs);
1040 initialized = true;
1041 }
1042
1043 return &netscapeFuncs;
1044}
1045
1046} // namespace WebKit
1047
1048#endif // ENABLE(NETSCAPE_PLUGIN_API)
1049