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