changeset 2197:eb4fd48b97cf

Message protocol overhaul to fix race conditions - Added unique reference identifiers to Java -> C++ requests so that the correct responses are serviced (fixes some bad race conditions when multiple applets are running). - Fix race conditions that caused some of the set tests to intermittently fail. 2010-03-09 Deepak Bhole <dbhole@redhat.com> * plugin/icedteanp/IcedTeaNPPlugin.cc (consume_message): Handle the new reference field and send it back when sending proxy and cookie info. (get_proxy_info): Update response format for proxy information to make it consistent with new Gecko API. * plugin/icedteanp/IcedTeaPluginRequestProcessor.cc (newMessageOnBus): Account for the new reference field and send it back with the response. (sendWindow): Same. (eval): Same. (call): Same. (sendString): Same. (setMember): Same. Also, move responding code from _setMember to setMember for consistency and to solve a rather bad race condition that affected reliability. (sendMember): Account for the new reference field and send it back with the response. (queue_processor): Move array index slots based on new positions with reference ids. (_setMember): Move response code back to setMember. * plugin/icedteanp/java/sun/applet/GetMemberPluginCallRequest.java (GetMemberPluginCallRequest): Change method signature to receive a reference identifier. (parse): Update to handle new reference identifiers. (serviceable): Removed method. serviceable() is now implemented in the parent class and uses unique reference identifiers. * plugin/icedteanp/java/sun/applet/GetWindowPluginCallRequest.java (GetWindowPluginCallRequest): Change method signature to receive a reference identifier. (serviceable): Removed method. serviceable() is now implemented in the parent class and uses unique reference identifiers. * plugin/icedteanp/java/sun/applet/PluginAppletViewer.java: Added new statis private requestIdentityCounter variable that provides unique reference numbers. (createPanel): Send a dummy (0) reference number with initialization msg. (getRequestIdentifier): New method. Returns a unique reference number and then increments requestIdentityCounter in a thread-safe manner. (getWindow): Send reference id to getPluginCallRequest. (getMember): Same. (setMember): Same. (setSlot): Same. (getSlot): Same. (eval): Same. (removeMember): Same. (call): Same. (requestPluginCookieInfo): Same. (requestPluginProxyInfo): Same. (JavaScriptFinalize): Same. (javascriptToString): Same. * plugin/icedteanp/java/sun/applet/PluginCallRequest.java: Track reference numbers instead of the 'return string' marker. (serviceable): Change from abstract to implemented method, returns weather or not the given message is servicable by this request based on unique reference numbers. * plugin/icedteanp/java/sun/applet/PluginCallRequestFactory.java (getPluginCallRequest): Pass reference numbers to concrete class constructors. * plugin/icedteanp/java/sun/applet/PluginCookieInfoRequest.java (PluginCookieInfoRequest): Receive new reference number and pass it to parent. (parseString): Update to handle new reference numbers in message. (serviceable): Removed method. serviceable() is now implemented in the parent class and uses unique reference identifiers. * plugin/icedteanp/java/sun/applet/PluginProxyInfoRequest.java (PluginProxyInfoRequest): Receive new reference number and pass it to parent. (parseReturn): Update to handle new reference numbers in message. Also, parse based on new format returned by the C++ side. (serviceable): Removed method. serviceable() is now implemented in the parent class and uses unique reference identifiers. * plugin/icedteanp/java/sun/applet/PluginStreamHandler.java (handleMessage): Pass reference to finishCallRequest(). * plugin/icedteanp/java/sun/applet/VoidPluginCallRequest.java (VoidPluginCallRequest): Update to handle new reference numbers in message. * plugin/tests/LiveConnect/common.js (testAll): Check eval tests checkbox before calling doTest();
author Deepak Bhole <dbhole@redhat.com>
date Tue, 01 Jun 2010 17:28:35 +0100
parents d9f8a98810eb
children 693114a512ea
files ChangeLog plugin/icedteanp/IcedTeaNPPlugin.cc plugin/icedteanp/IcedTeaPluginRequestProcessor.cc plugin/icedteanp/java/sun/applet/GetMemberPluginCallRequest.java plugin/icedteanp/java/sun/applet/GetWindowPluginCallRequest.java plugin/icedteanp/java/sun/applet/PluginAppletViewer.java plugin/icedteanp/java/sun/applet/PluginCallRequest.java plugin/icedteanp/java/sun/applet/PluginCallRequestFactory.java plugin/icedteanp/java/sun/applet/PluginCookieInfoRequest.java plugin/icedteanp/java/sun/applet/PluginProxyInfoRequest.java plugin/icedteanp/java/sun/applet/PluginStreamHandler.java plugin/icedteanp/java/sun/applet/VoidPluginCallRequest.java plugin/tests/LiveConnect/common.js
diffstat 13 files changed, 265 insertions(+), 175 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Tue Jun 01 16:12:06 2010 +0100
+++ b/ChangeLog	Tue Jun 01 17:28:35 2010 +0100
@@ -1,3 +1,83 @@
+2010-03-09  Deepak Bhole <dbhole@redhat.com>
+
+	* plugin/icedteanp/IcedTeaNPPlugin.cc
+	(consume_message): Handle the new reference field and send it back when
+	sending proxy and cookie info.
+	(get_proxy_info): Update response format for proxy information to make it
+	consistent with new Gecko API.
+	* plugin/icedteanp/IcedTeaPluginRequestProcessor.cc
+	(newMessageOnBus): Account for the new reference field and send it back
+	with the response.
+	(sendWindow): Same.
+	(eval): Same.
+	(call): Same.
+	(sendString): Same.
+	(setMember): Same. Also, move responding code from _setMember to setMember
+	for consistency and to solve a rather bad race condition that affected
+	reliability.
+	(sendMember): Account for the new reference field and send it back 
+	with the response.
+	(queue_processor): Move array index slots based on new positions with
+	reference ids.
+	(_setMember): Move response code back to setMember.
+	* plugin/icedteanp/java/sun/applet/GetMemberPluginCallRequest.java
+	(GetMemberPluginCallRequest): Change method signature to receive a
+	reference identifier.
+	(parse): Update to handle new reference identifiers.
+	(serviceable): Removed method. serviceable() is now implemented in the
+	parent class and uses unique reference identifiers.
+	* plugin/icedteanp/java/sun/applet/GetWindowPluginCallRequest.java
+	(GetWindowPluginCallRequest): Change method signature to receive a 
+	reference identifier.
+	(serviceable): Removed method. serviceable() is now implemented in the
+	parent class and uses unique reference identifiers.
+	* plugin/icedteanp/java/sun/applet/PluginAppletViewer.java: Added new
+	statis private requestIdentityCounter variable that provides unique
+	reference numbers.
+	(createPanel): Send a dummy (0) reference number with initialization msg.
+	(getRequestIdentifier): New method. Returns a unique reference number 
+	and then increments requestIdentityCounter in a thread-safe manner.
+	(getWindow): Send reference id to getPluginCallRequest.
+	(getMember): Same.
+	(setMember): Same.
+	(setSlot): Same.
+	(getSlot): Same.
+	(eval): Same.
+	(removeMember): Same.
+	(call): Same.
+	(requestPluginCookieInfo): Same.
+	(requestPluginProxyInfo): Same.
+	(JavaScriptFinalize): Same.
+	(javascriptToString): Same.
+	* plugin/icedteanp/java/sun/applet/PluginCallRequest.java: Track reference
+	numbers instead of the 'return string' marker.
+	(serviceable): Change from abstract to implemented method, returns weather
+	or not the given message is servicable by this request based on unique
+	reference numbers.
+	* plugin/icedteanp/java/sun/applet/PluginCallRequestFactory.java
+	(getPluginCallRequest): Pass reference numbers to concrete class
+	constructors.
+	* plugin/icedteanp/java/sun/applet/PluginCookieInfoRequest.java
+	(PluginCookieInfoRequest): Receive new reference number and pass it to
+	parent.
+	(parseString): Update to handle new reference numbers in message.
+	(serviceable): Removed method. serviceable() is now implemented in the
+	parent class and uses unique reference identifiers.
+	* plugin/icedteanp/java/sun/applet/PluginProxyInfoRequest.java
+	(PluginProxyInfoRequest): Receive new reference number and pass it to
+	parent.
+	(parseReturn): Update to handle new reference numbers in message. Also,
+	parse based on new format returned by the C++ side.
+	(serviceable): Removed method. serviceable() is now implemented in the
+	parent class and uses unique reference identifiers.
+	* plugin/icedteanp/java/sun/applet/PluginStreamHandler.java
+	(handleMessage): Pass reference to finishCallRequest().
+	* plugin/icedteanp/java/sun/applet/VoidPluginCallRequest.java
+	(VoidPluginCallRequest): Update to handle new reference numbers in
+	message.
+	* plugin/tests/LiveConnect/common.js
+	(testAll): Check eval tests checkbox before calling doTest();
+
 2010-03-08  Andrew John Hughes  <ahughes@redhat.com>
 
 	* Makefile.am:
--- a/plugin/icedteanp/IcedTeaNPPlugin.cc	Tue Jun 01 16:12:06 2010 +0100
+++ b/plugin/icedteanp/IcedTeaNPPlugin.cc	Tue Jun 01 17:28:35 2010 +0100
@@ -1222,15 +1222,15 @@
   else if (g_str_has_prefix (message, "plugin "))
     {
       // internal plugin related message
-      gchar** parts = g_strsplit (message, " ", 3);
+      gchar** parts = g_strsplit (message, " ", 5);
       if (g_str_has_prefix(parts[1], "PluginProxyInfo"))
       {
         gchar* proxy;
         uint32_t len;
 
-        gchar* decoded_url = (gchar*) calloc(strlen(parts[2]) + 1, sizeof(gchar));
-        IcedTeaPluginUtilities::decodeURL(parts[2], &decoded_url);
-        PLUGIN_DEBUG_4ARG("parts[0]=%s, parts[1]=%s, parts[2]=%s -- decoded_url=%s\n", parts[0], parts[1], parts[2], decoded_url);
+        gchar* decoded_url = (gchar*) calloc(strlen(parts[4]) + 1, sizeof(gchar));
+        IcedTeaPluginUtilities::decodeURL(parts[4], &decoded_url);
+        PLUGIN_DEBUG_5ARG("parts[0]=%s, parts[1]=%s, reference, parts[3]=%s, parts[4]=%s -- decoded_url=%s\n", parts[0], parts[1], parts[3], parts[4], decoded_url);
 
         gchar* proxy_info;
 
@@ -1238,7 +1238,7 @@
 	proxy = (char*) malloc(sizeof(char)*2048);
 #endif
 
-        proxy_info = g_strconcat ("plugin PluginProxyInfo ", NULL);
+        proxy_info = g_strconcat ("plugin PluginProxyInfo reference ", parts[3], " ", NULL);
         if (get_proxy_info(decoded_url, &proxy, &len) == NPERR_NO_ERROR)
           {
             proxy_info = g_strconcat (proxy_info, proxy, NULL);
@@ -1259,10 +1259,10 @@
 
       } else if (g_str_has_prefix(parts[1], "PluginCookieInfo"))
       {
-        gchar* decoded_url = (gchar*) calloc(strlen(parts[2])+1, sizeof(gchar));
-        IcedTeaPluginUtilities::decodeURL(parts[2], &decoded_url);
+        gchar* decoded_url = (gchar*) calloc(strlen(parts[4])+1, sizeof(gchar));
+        IcedTeaPluginUtilities::decodeURL(parts[4], &decoded_url);
 
-        gchar* cookie_info = g_strconcat ("plugin PluginCookieInfo ", parts[2], " ", NULL);
+        gchar* cookie_info = g_strconcat ("plugin PluginCookieInfo reference ", parts[3], " ", NULL);
         gchar* cookie_string;
         uint32_t len;
         if (get_cookie_info(decoded_url, &cookie_string, &len) == NPERR_NO_ERROR)
@@ -1358,7 +1358,14 @@
   nsDependentCString ipAddr;
   record->GetNextAddrAsString(ipAddr);
 
-  snprintf(*proxy, sizeof(char)*1024, "%s://%s:%d", ptype.get(), ipAddr.get(), pport);
+  if (!strcmp(ptype.get(), "http"))
+  {
+      snprintf(*proxy, sizeof(char)*1024, "%s %s:%d", "PROXY", ipAddr.get(), pport);
+  } else
+  {
+      snprintf(*proxy, sizeof(char)*1024, "%s %s:%d", "SOCKS", ipAddr.get(), pport);
+  }
+
   *len = strlen(*proxy);
 
   PLUGIN_DEBUG_2ARG("Proxy info for %s: %s\n", siteAddr, *proxy);
--- a/plugin/icedteanp/IcedTeaPluginRequestProcessor.cc	Tue Jun 01 16:12:06 2010 +0100
+++ b/plugin/icedteanp/IcedTeaPluginRequestProcessor.cc	Tue Jun 01 17:28:35 2010 +0100
@@ -103,7 +103,7 @@
     IcedTeaPluginUtilities::printStringVector("PluginRequestProcessor::newMessageOnBus:", message_parts);
 
     type = message_parts->at(0);
-    command = message_parts->at(2);
+    command = message_parts->at(4);
 
     if (type == "instance")
     {
@@ -122,7 +122,7 @@
                    command == "Eval")
         {
 
-        	// Update queue synchronously
+            // Update queue synchronously
         	pthread_mutex_lock(&message_queue_mutex);
             message_queue->push_back(message_parts);
             pthread_mutex_unlock(&message_queue_mutex);
@@ -152,6 +152,7 @@
 {
     std::string type;
     std::string command;
+    int reference;
     std::string response = std::string();
     std::string window_ptr_str = std::string();
     NPVariant* variant = new NPVariant();
@@ -160,7 +161,8 @@
 
     type = message_parts->at(0);
     id = atoi(message_parts->at(1).c_str());
-    command = message_parts->at(2);
+    reference = atoi(message_parts->at(3).c_str());
+    command = message_parts->at(4);
 
     NPP instance;
     get_instance_from_id(id, instance);
@@ -173,7 +175,7 @@
     IcedTeaPluginUtilities::JSIDToString(variant, &window_ptr_str);
 
     // We need the context 0 for backwards compatibility with the Java side
-    IcedTeaPluginUtilities::constructMessagePrefix(0, &response);
+    IcedTeaPluginUtilities::constructMessagePrefix(0, reference, &response);
     response += " JavaScriptGetWindow ";
     response += window_ptr_str;
 
@@ -201,14 +203,16 @@
     NPP instance;
     std::string script;
     NPVariant result;
+    int reference;
     std::string response = std::string();
     std::string return_type = std::string();
     int id;
 
-    window_ptr = (NPVariant*) IcedTeaPluginUtilities::stringToJSID(message_parts->at(3));
+    reference = atoi(message_parts->at(3).c_str());
+    window_ptr = (NPVariant*) IcedTeaPluginUtilities::stringToJSID(message_parts->at(5));
     instance = IcedTeaPluginUtilities::getInstanceFromMemberPtr(window_ptr);
 
-    java_result = request_processor.getString(message_parts->at(4));
+    java_result = request_processor.getString(message_parts->at(6));
     CHECK_JAVA_RESULT(java_result);
     script.append(*(java_result->return_string));
 
@@ -240,7 +244,7 @@
     std::string result_variant_jniid = std::string();
     createJavaObjectFromVariant(instance, *result_variant, &result_variant_jniid);
 
-    IcedTeaPluginUtilities::constructMessagePrefix(0, &response);
+    IcedTeaPluginUtilities::constructMessagePrefix(0, reference, &response);
     response += " JavaScriptEval ";
     response += result_variant_jniid;
 
@@ -262,6 +266,7 @@
     NPP instance;
     std::string window_ptr_str;
     NPVariant* window_ptr;
+    int reference;
     std::string window_function_name;
     std::vector<NPVariant> args = std::vector<NPVariant>();
     std::vector<std::string> arg_ids = std::vector<std::string>();
@@ -270,20 +275,22 @@
     JavaRequestProcessor java_request = JavaRequestProcessor();
     JavaResultData* java_result;
 
+    reference = atoi(message_parts->at(3).c_str());
+
     // window
-    window_ptr_str = message_parts->at(3);
+    window_ptr_str = message_parts->at(5);
     window_ptr = (NPVariant*) IcedTeaPluginUtilities::stringToJSID(window_ptr_str);
 
     // instance
     instance = IcedTeaPluginUtilities::getInstanceFromMemberPtr(window_ptr);
 
     // function name
-    java_result = java_request.getString(message_parts->at(4));
+    java_result = java_request.getString(message_parts->at(6));
     CHECK_JAVA_RESULT(java_result);
     window_function_name.append(*(java_result->return_string));
 
     // arguments
-    for (int i=5; i < message_parts->size(); i++)
+    for (int i=7; i < message_parts->size(); i++)
     {
         arg_ids.push_back(message_parts->at(i));
     }
@@ -342,7 +349,7 @@
         result_variant_jniid = "0";
     }
 
-    IcedTeaPluginUtilities::constructMessagePrefix(0, &response);
+    IcedTeaPluginUtilities::constructMessagePrefix(0, reference, &response);
     response += " JavaScriptCall ";
     response += result_variant_jniid;
 
@@ -364,9 +371,11 @@
     NPVariant* variant;
     JavaRequestProcessor java_request = JavaRequestProcessor();
     JavaResultData* java_result;
+    int reference;
     std::string response = std::string();
 
-    variant_ptr = message_parts->at(3);
+    reference = atoi(message_parts->at(3).c_str());
+    variant_ptr = message_parts->at(5);
 
     variant = (NPVariant*) IcedTeaPluginUtilities::stringToJSID(variant_ptr);
     AsyncCallThreadData thread_data = AsyncCallThreadData();
@@ -393,7 +402,7 @@
 #endif
 
     // We need the context 0 for backwards compatibility with the Java side
-    IcedTeaPluginUtilities::constructMessagePrefix(0, &response);
+    IcedTeaPluginUtilities::constructMessagePrefix(0, reference, &response);
     response += " JavaScriptToString ";
     response += thread_data.result;
 
@@ -418,6 +427,8 @@
 {
     std::string propertyNameID;
     std::string value = std::string();
+    std::string response = std::string();
+    int reference;
 
     NPP instance;
     NPVariant* member;
@@ -428,24 +439,26 @@
 
     IcedTeaPluginUtilities::printStringVector("PluginRequestProcessor::_setMember - ", message_parts);
 
-    member = (NPVariant*) (IcedTeaPluginUtilities::stringToJSID(message_parts->at(3)));
-    propertyNameID = message_parts->at(4);
+    reference = atoi(message_parts->at(3).c_str());
+
+    member = (NPVariant*) (IcedTeaPluginUtilities::stringToJSID(message_parts->at(5)));
+    propertyNameID = message_parts->at(6);
 
-    if (message_parts->at(5) == "literalreturn")
+    if (message_parts->at(7) == "literalreturn")
     {
-        value.append(message_parts->at(5));
+        value.append(message_parts->at(7));
         value.append(" ");
-        value.append(message_parts->at(6));
+        value.append(message_parts->at(8));
     } else
     {
-        value.append(message_parts->at(5));
+        value.append(message_parts->at(7));
     }
 
     instance = IcedTeaPluginUtilities::getInstanceFromMemberPtr(member);
 
-    if (message_parts->at(2) == "SetSlot")
+    if (message_parts->at(4) == "SetSlot")
     {
-        property_identifier = browser_functions.getintidentifier(atoi(message_parts->at(4).c_str()));
+        property_identifier = browser_functions.getintidentifier(atoi(message_parts->at(6).c_str()));
     } else
     {
         java_result = java_request.getString(propertyNameID);
@@ -476,6 +489,10 @@
     }
 #endif
 
+    IcedTeaPluginUtilities::constructMessagePrefix(0, reference, &response);
+    response.append(" JavaScriptSetMember ");
+    plugin_to_java_bus->post(response.c_str());
+
     cleanup:
     delete message_parts;
 
@@ -505,6 +522,7 @@
     JavaResultData* java_result;
     NPVariant* parent_ptr;
 
+    //int reference;
     std::string member_id = std::string();
     std::string jsObjectClassID = std::string();
     std::string jsObjectConstructorID = std::string();
@@ -516,18 +534,20 @@
 
     int method_id;
     int instance_id;
-    long reference;
+    int reference;
 
     // debug printout of parent thread data
     IcedTeaPluginUtilities::printStringVector("PluginRequestProcessor::getMember:", message_parts);
 
+    reference = atoi(message_parts->at(3).c_str());
+
     // store info in local variables for easy access
     instance_id = atoi(message_parts->at(1).c_str());
-    parent_ptr = (NPVariant*) (IcedTeaPluginUtilities::stringToJSID(message_parts->at(3)));
-    member_id += message_parts->at(4);
+    parent_ptr = (NPVariant*) (IcedTeaPluginUtilities::stringToJSID(message_parts->at(5)));
+    member_id += message_parts->at(6);
 
     /** Request data from Java if necessary **/
-    if (message_parts->at(2) == "GetSlot")
+    if (message_parts->at(4) == "GetSlot")
     {
         member_identifier = browser_functions.getintidentifier(atoi(member_id.c_str()));
     } else
@@ -545,10 +565,6 @@
         member_identifier = browser_functions.getstringidentifier(java_result->return_string->c_str());
     }
 
-    /** Make an internal request for the main thread to handle, to get the member pointer **/
-
-    reference = internal_req_ref_counter++;
-
     AsyncCallThreadData thread_data = AsyncCallThreadData();
     thread_data.result_ready = false;
     thread_data.parameters = std::vector<void*>();
@@ -577,8 +593,6 @@
 
     PLUGIN_DEBUG_1ARG("Member PTR after internal request: %s\n", thread_data.result.c_str());
 
-    internal_req_ref_counter--;
-
     java_result = java_request.findClass(0, "netscape.javascript.JSObject");
 
     // the result we want is in result_string (assuming there was no error)
@@ -624,7 +638,7 @@
     }
 
 
-    IcedTeaPluginUtilities::constructMessagePrefix(0, &response);
+    IcedTeaPluginUtilities::constructMessagePrefix(0, reference, &response);
     if (message_parts->at(2) == "GetSlot")
     {
         response.append(" JavaScriptGetMember ");
@@ -667,7 +681,7 @@
 
         if (message_parts)
         {
-            command = message_parts->at(2);
+            command = message_parts->at(4);
 
             if (command == "GetMember")
             {
@@ -732,7 +746,6 @@
 _setMember(void* data)
 {
     std::string* value;
-    std::string response = std::string();
 
     NPP instance;
     NPVariant value_variant = NPVariant();
@@ -753,12 +766,7 @@
 
     ((AsyncCallThreadData*) data)->call_successful = browser_functions.setproperty(instance, member, *property, &value_variant);
 
-    IcedTeaPluginUtilities::constructMessagePrefix(0, &response);
-    response.append(" JavaScriptSetMember ");
-    plugin_to_java_bus->post(response.c_str());
-
     ((AsyncCallThreadData*) data)->result_ready = true;
-
 }
 
 void
--- a/plugin/icedteanp/java/sun/applet/GetMemberPluginCallRequest.java	Tue Jun 01 16:12:06 2010 +0100
+++ b/plugin/icedteanp/java/sun/applet/GetMemberPluginCallRequest.java	Tue Jun 01 17:28:35 2010 +0100
@@ -41,35 +41,21 @@
 public class GetMemberPluginCallRequest extends PluginCallRequest {
     Object object = null;
 
-    public GetMemberPluginCallRequest(String message, String returnString) {
-        super(message, returnString);
-        PluginDebug.debug ("GetMEMBerPLUGINCAlL " + message + " " + returnString);
+    public GetMemberPluginCallRequest(String message, Long reference) {
+        super(message, reference);
+        PluginDebug.debug ("GetMemberPluginCall " + message);
     }
 
     public void parseReturn(String message) {
-    	PluginDebug.debug ("GetMEMBerparseReturn GOT: " + message);
+    	PluginDebug.debug ("GetMemberParseReturn GOT: " + message);
         String[] args = message.split(" ");
         // FIXME: Is it even possible to distinguish between null and void
         // here?
-        if (args[1] != "null" && args[1] != "void")
-        	object = AppletSecurityContextManager.getSecurityContext(0).getObject(Integer.parseInt(args[1]));
+        if (args[3] != "null" && args[3] != "void")
+        	object = AppletSecurityContextManager.getSecurityContext(0).getObject(Integer.parseInt(args[3]));
         setDone(true);
     }
 
-    /**
-     * Returns whether the given message is serviceable by this object
-     * 
-     * @param message The message to service
-     * @return boolean indicating if message is serviceable
-     */
-    public boolean serviceable(String message) {
-    	return message.contains("JavaScriptCall") ||
-    			message.contains("JavaScriptEval") ||
-    			message.contains("JavaScriptGetMember") ||
-    			message.contains("JavaScriptGetSlot") ||
-    			message.contains("JavaScriptToString");
-    }
-    
     public Object getObject() {
     	return this.object;
     }
--- a/plugin/icedteanp/java/sun/applet/GetWindowPluginCallRequest.java	Tue Jun 01 16:12:06 2010 +0100
+++ b/plugin/icedteanp/java/sun/applet/GetWindowPluginCallRequest.java	Tue Jun 01 17:28:35 2010 +0100
@@ -46,28 +46,18 @@
     // FIXME: look into int vs long JavaScript internal values.
     long internal;
 
-    public GetWindowPluginCallRequest(String message, String returnString) {
-        super(message, returnString);
+    public GetWindowPluginCallRequest(String message, Long reference) {
+        super(message, reference);
     }
 
     public void parseReturn(String message) {
-    	PluginDebug.debug ("GetWINDOWparseReturn GOT: " + message);
+    	PluginDebug.debug ("GetWindowParseReturn GOT: " + message);
         String[] args = message.split(" ");
         // FIXME: add thread ID to messages to support multiple
         // threads using the netscape.javascript package.
-        internal = Long.parseLong(args[1]);
+        internal = Long.parseLong(args[3]);
         setDone(true);
     }
-    
-    /**
-     * Returns whether the given message is serviceable by this object
-     * 
-     * @param message The message to service
-     * @return boolean indicating if message is serviceable
-     */
-    public boolean serviceable(String message) {
-    	return message.contains("JavaScriptGetWindow");
-    }
 
     public Long getObject() {
     	return this.internal;
--- a/plugin/icedteanp/java/sun/applet/PluginAppletViewer.java	Tue Jun 01 16:12:06 2010 +0100
+++ b/plugin/icedteanp/java/sun/applet/PluginAppletViewer.java	Tue Jun 01 17:28:35 2010 +0100
@@ -209,7 +209,7 @@
          }
 
          PluginDebug.debug("Applet " + a.getClass() + " initialized");
-         streamhandler.write("instance " + identifier + " initialized");
+         streamhandler.write("instance " + identifier + " reference 0 initialized");
 
          AppletSecurityContextManager.getSecurityContext(0).associateSrc(((NetxPanel) panel).getAppletClassLoader(), doc);
          AppletSecurityContextManager.getSecurityContext(0).associateInstance(identifier, ((NetxPanel) panel).getAppletClassLoader());
@@ -368,9 +368,11 @@
      private long handle = 0;
      private WindowListener windowEventListener = null;
      private AppletEventListener appletEventListener = null;
-     
+
      public static final int APPLET_TIMEOUT = 60000;
 
+     private static Long requestIdentityCounter = 0L;
+
      /**
       * Null constructor to allow instantiation via newInstance()
       */
@@ -949,11 +951,30 @@
         }
      }
 
+     /**
+      * Returns an incremental number (unique identifier) for a message.
+      * If identifier hits Long.MAX_VALUE it loops back starting at 0.
+      *
+      *  @return A unique Long identifier for the request
+      */
+     private static Long getRequestIdentifier() {
+         synchronized (requestIdentityCounter) {
+
+             if (requestIdentityCounter == Long.MAX_VALUE)
+                 requestIdentityCounter = 0L;
+
+             return requestIdentityCounter++;
+        }
+     }
+
      public long getWindow() {
          PluginDebug.debug ("STARTING getWindow");
+         Long reference = getRequestIdentifier();
+
          PluginCallRequest request = requestFactory.getPluginCallRequest("window",
-                                                                                "instance " + identifier + " " + "GetWindow",
-                                                                                "JavaScriptGetWindow");
+             "instance " + identifier + " reference " +
+             + reference + " " + "GetWindow", reference);
+
          PluginDebug.debug ("STARTING postCallRequest");
                  streamhandler.postCallRequest(request);
          PluginDebug.debug ("STARTING postCallRequest done");
@@ -980,11 +1001,13 @@
      {
          AppletSecurityContextManager.getSecurityContext(0).store(name);
          int nameID = AppletSecurityContextManager.getSecurityContext(0).getIdentifier(name);
+         Long reference = getRequestIdentifier();
 
          // Prefix with dummy instance for convenience.
          PluginCallRequest request = requestFactory.getPluginCallRequest("member",
-                                                                                "instance " + 0 + " GetMember " + internal + " " + nameID,
-                                                                                "JavaScriptGetMember");
+             "instance " + 0 + " reference " + reference + " GetMember " +
+             internal + " " + nameID, reference);
+
          streamhandler.postCallRequest(request);
          streamhandler.write(request.getMessage());
          try {
@@ -1007,6 +1030,7 @@
          System.err.println("Setting to class " + value.getClass() + ":" + value.getClass().isPrimitive());
          AppletSecurityContextManager.getSecurityContext(0).store(name);
          int nameID = AppletSecurityContextManager.getSecurityContext(0).getIdentifier(name);
+         Long reference = getRequestIdentifier();
 
          // work on a copy of value, as we don't want to be manipulating
          // complex objects
@@ -1038,10 +1062,9 @@
 
          // Prefix with dummy instance for convenience.
          PluginCallRequest request = requestFactory.getPluginCallRequest("void",
-                                                                         "instance " + 0 +
-                                                                         " SetMember " + internal +
-                                                                         " " + nameID + " " + valueToSetTo,
-                                                                         "JavaScriptSetMember");
+             "instance " + 0 + " reference " + reference + " SetMember " +
+             internal + " " + nameID + " " + valueToSetTo, reference);
+
          streamhandler.postCallRequest(request);
          streamhandler.write(request.getMessage());
          try {
@@ -1063,6 +1086,7 @@
      // FIXME: handle long index as well.
      public static void setSlot(long internal, int index, Object value) {
          AppletSecurityContextManager.getSecurityContext(0).store(value);
+         Long reference = getRequestIdentifier();
 
          // work on a copy of value, as we don't want to be manipulating
          // complex objects
@@ -1094,10 +1118,9 @@
 
          // Prefix with dummy instance for convenience.
          PluginCallRequest request = requestFactory.getPluginCallRequest("void",
-                                                                        "instance " + 0 +
-                                                                         " SetSlot " + internal +
-                                                                         " " + index + " " + valueToSetTo,
-                                                                         "JavaScriptSetSlot");
+             "instance " + 0 + " reference " + reference + " SetSlot " +
+             internal + " " + index + " " + valueToSetTo, reference);
+
          streamhandler.postCallRequest(request);
          streamhandler.write(request.getMessage());
          try {
@@ -1117,10 +1140,12 @@
 
      public static Object getSlot(long internal, int index)
      {
+         Long reference = getRequestIdentifier();
+
          // Prefix with dummy instance for convenience.
          PluginCallRequest request = requestFactory.getPluginCallRequest("member",
-                                                                                        "instance " + 0 + " GetSlot " + internal + " " + index,
-                                                                                        "JavaScriptGetSlot");
+             "instance " + 0 + " reference " + reference + " GetSlot " +
+             internal + " " + index, reference);
          streamhandler.postCallRequest(request);
          streamhandler.write(request.getMessage());
          try {
@@ -1143,11 +1168,13 @@
      {
          AppletSecurityContextManager.getSecurityContext(0).store(s);
          int stringID = AppletSecurityContextManager.getSecurityContext(0).getIdentifier(s);
+         Long reference = getRequestIdentifier();
+
          // Prefix with dummy instance for convenience.
          // FIXME: rename GetMemberPluginCallRequest ObjectPluginCallRequest.
          PluginCallRequest request = requestFactory.getPluginCallRequest("member",
-                                                                                        "instance " + 0 + " Eval " + internal + " " + stringID,
-                                                                                        "JavaScriptEval");
+             "instance " + 0 + " reference " + reference + " Eval " +
+             internal + " " + stringID, reference);
          streamhandler.postCallRequest(request);
          streamhandler.write(request.getMessage());
          try {
@@ -1169,11 +1196,13 @@
      public static void removeMember (long internal, String name) {
          AppletSecurityContextManager.getSecurityContext(0).store(name);
          int nameID = AppletSecurityContextManager.getSecurityContext(0).getIdentifier(name);
+         Long reference = getRequestIdentifier();
 
          // Prefix with dummy instance for convenience.
          PluginCallRequest request = requestFactory.getPluginCallRequest("void",
-                                                                        "instance " + 0 + " RemoveMember " + internal + " " + nameID,
-                                                                        "JavaScriptRemoveMember");
+             "instance " + 0 + " reference " + reference + " RemoveMember " +
+             internal + " " + nameID, reference);
+
          streamhandler.postCallRequest(request);
          streamhandler.write(request.getMessage());
          try {
@@ -1198,6 +1227,7 @@
          // FIXME: convenience method for this long line.
          AppletSecurityContextManager.getSecurityContext(0).store(name);
          int nameID = AppletSecurityContextManager.getSecurityContext(0).getIdentifier(name);
+         Long reference = getRequestIdentifier();
 
          String argIDs = "";
          for (Object arg : args)
@@ -1209,8 +1239,9 @@
 
          // Prefix with dummy instance for convenience.
          PluginCallRequest request = requestFactory.getPluginCallRequest("member",
-                                                                                "instance " + 0 + " Call " + internal + " " + nameID + " " + argIDs,
-                                                                                "JavaScriptCall");
+             "instance " + 0 + " reference " + reference + " Call " +
+             internal + " " + nameID + " " + argIDs, reference);
+
          streamhandler.postCallRequest(request);
          streamhandler.write(request.getMessage());
          try {
@@ -1232,12 +1263,14 @@
      public static Object requestPluginCookieInfo(URI uri) {
 
          PluginCallRequest request;
+         Long reference = getRequestIdentifier();
+
          try
          {
              String encodedURI = UrlUtil.encode(uri.toString(), "UTF-8");
              request = requestFactory.getPluginCallRequest("cookieinfo",
-                               "plugin PluginCookieInfo " + encodedURI,
-                               "plugin PluginCookieInfo " + encodedURI);
+                 "plugin PluginCookieInfo " + "reference " + reference +
+                 " " + encodedURI, reference);
 
          } catch (UnsupportedEncodingException e)
          {
@@ -1266,6 +1299,7 @@
      public static Object requestPluginProxyInfo(URI uri) {
 
          String requestURI = null;
+         Long reference = getRequestIdentifier();
 
          try {
 
@@ -1286,8 +1320,9 @@
          }
 
          PluginCallRequest request = requestFactory.getPluginCallRequest("proxyinfo",
-                                            "plugin PluginProxyInfo " + requestURI,
-                                            "plugin");
+             "plugin PluginProxyInfo reference " + reference + " " +
+             requestURI, reference);
+
          streamhandler.postCallRequest(request);
          streamhandler.write(request.getMessage());
          try {
@@ -1308,10 +1343,13 @@
 
      public static void JavaScriptFinalize(long internal)
      {
+         Long reference = getRequestIdentifier();
+
          // Prefix with dummy instance for convenience.
          PluginCallRequest request = requestFactory.getPluginCallRequest("void",
-                                                                        "instance " + 0 + " Finalize " + internal,
-                                                                        "JavaScriptFinalize");
+             "instance " + 0 + " reference " + reference + " Finalize " +
+             internal, reference);
+
          streamhandler.postCallRequest(request);
          streamhandler.write(request.getMessage());
          try {
@@ -1331,10 +1369,13 @@
 
      public static String javascriptToString(long internal)
      {
+         Long reference = getRequestIdentifier();
+
          // Prefix with dummy instance for convenience.
          PluginCallRequest request = requestFactory.getPluginCallRequest("member",
-                                                                                        "instance " + 0 + " ToString " + internal,
-                                                                                        "JavaScriptToString");
+             "instance " + 0 + " reference " + reference + " ToString " +
+             internal, reference);
+
          streamhandler.postCallRequest(request);
          streamhandler.write(request.getMessage());
          try {
--- a/plugin/icedteanp/java/sun/applet/PluginCallRequest.java	Tue Jun 01 16:12:06 2010 +0100
+++ b/plugin/icedteanp/java/sun/applet/PluginCallRequest.java	Tue Jun 01 17:28:35 2010 +0100
@@ -44,23 +44,19 @@
 // PluginCallRequest.
 public abstract class PluginCallRequest {
     String message;
-    String returnString;
+    Long reference;
     PluginCallRequest next;
     boolean done = false;
 
-    public PluginCallRequest(String message, String returnString) {
+    public PluginCallRequest(String message, Long reference) {
         this.message = message;
-        this.returnString = returnString;
+        this.reference = reference;
     }
 
     public String getMessage() {
     	return this.message;
     }
     
-    public String getReturnString() {
-    	return this.returnString;
-    }
-    
     public boolean isDone() {
     	return this.done;
     }
@@ -77,9 +73,17 @@
     	return this.next;
     }
 
-    public abstract void parseReturn(String message);
+    /**
+     * Returns whether the given message is serviceable by this object
+     * 
+     * @param message The message to service
+     * @return boolean indicating if message is serviceable
+     */
+    public boolean serviceable(String message) {
+        return message.contains("reference " + reference);
+    }
     
-    public abstract boolean serviceable(String message);
+    public abstract void parseReturn(String message);
     
     public abstract Object getObject();
 }
--- a/plugin/icedteanp/java/sun/applet/PluginCallRequestFactory.java	Tue Jun 01 16:12:06 2010 +0100
+++ b/plugin/icedteanp/java/sun/applet/PluginCallRequestFactory.java	Tue Jun 01 17:28:35 2010 +0100
@@ -40,19 +40,19 @@
 
 
 public class PluginCallRequestFactory {
-
-	public PluginCallRequest getPluginCallRequest(String id, String message, String returnString) {
+    
+	public PluginCallRequest getPluginCallRequest(String id, String message, Long reference) {
 
 		if (id == "member") {
-			return new GetMemberPluginCallRequest(message, returnString);
+			return new GetMemberPluginCallRequest(message, reference);
 		} else if (id == "void") {
-			return new VoidPluginCallRequest(message, returnString);
+			return new VoidPluginCallRequest(message, reference);
 		} else if (id == "window") {
-			return new GetWindowPluginCallRequest(message, returnString);
+			return new GetWindowPluginCallRequest(message, reference);
 		} else if (id == "proxyinfo") {
-            return new PluginProxyInfoRequest(message, returnString);
+            return new PluginProxyInfoRequest(message, reference);
         } else if (id == "cookieinfo") {
-            return new PluginCookieInfoRequest(message, returnString);
+            return new PluginCookieInfoRequest(message, reference);
         } else {
 			throw new RuntimeException ("Unknown plugin call request type requested from factory");
 		}
--- a/plugin/icedteanp/java/sun/applet/PluginCookieInfoRequest.java	Tue Jun 01 16:12:06 2010 +0100
+++ b/plugin/icedteanp/java/sun/applet/PluginCookieInfoRequest.java	Tue Jun 01 17:28:35 2010 +0100
@@ -46,10 +46,10 @@
 
     String cookieString = new String();
 
-    public PluginCookieInfoRequest(String message, String returnString) {
-        super(message, returnString);
+    public PluginCookieInfoRequest(String message, Long reference) {
+        super(message, reference);
     }
-    
+
     public void parseReturn(String cookieInfo) {
 
         // try to parse the proxy information. If things go wrong, do nothing .. 
@@ -57,25 +57,17 @@
 
     	PluginDebug.debug ("PluginCookieInfoRequest GOT: " + cookieInfo);
 
-    	// Skip the first 3 components. We are guaranteed 3 components, 
+    	// Skip the first 5 components. We are guaranteed 5 components, 
     	// so no index -1 to worry about
     	cookieInfo = cookieInfo.substring(cookieInfo.indexOf(' ')+1);
     	cookieInfo = cookieInfo.substring(cookieInfo.indexOf(' ')+1);
+    	cookieInfo = cookieInfo.substring(cookieInfo.indexOf(' ')+1);
+    	cookieInfo = cookieInfo.substring(cookieInfo.indexOf(' ')+1);
     	cookieString = cookieInfo.substring(cookieInfo.indexOf(' ')+1);
 
         setDone(true);
     }
 
-    /**
-     * Returns whether the given message is serviceable by this object
-     * 
-     * @param message The message to service
-     * @return boolean indicating if message is serviceable
-     */
-    public boolean serviceable(String message) {
-    	return message.startsWith(returnString);
-    }
-
     public String getObject() {
     	return this.cookieString;
     }
--- a/plugin/icedteanp/java/sun/applet/PluginProxyInfoRequest.java	Tue Jun 01 16:12:06 2010 +0100
+++ b/plugin/icedteanp/java/sun/applet/PluginProxyInfoRequest.java	Tue Jun 01 17:28:35 2010 +0100
@@ -48,8 +48,8 @@
     
     URI internal = null;
 
-    public PluginProxyInfoRequest(String message, String returnString) {
-        super(message, returnString);
+    public PluginProxyInfoRequest(String message, Long reference) {
+        super(message, reference);
     }
     
     public void parseReturn(String proxyInfo) {
@@ -61,24 +61,18 @@
     	String[] messageComponents = proxyInfo.split(" ");
 
     	try {
-    	    internal = new URI(messageComponents[2], null, messageComponents[3], Integer.parseInt(messageComponents[4]), null, null, null);
+    	    String protocol = messageComponents[4].equals("PROXY") ? "http" : "socks";
+    	    String host = messageComponents[5].split(":")[0];
+    	    int port = Integer.parseInt(messageComponents[5].split(":")[1]);
+
+    	    internal = new URI(protocol, null, host, port, null, null, null);
     	} catch (Exception e) {
-    	    // do nothing
+    	    e.printStackTrace();
     	}
 
         setDone(true);
     }
 
-    /**
-     * Returns whether the given message is serviceable by this object
-     * 
-     * @param message The message to service
-     * @return boolean indicating if message is serviceable
-     */
-    public boolean serviceable(String message) {
-    	return message.startsWith("plugin PluginProxyInfo");
-    }
-
     public URI getObject() {
     	return this.internal;
     }
--- a/plugin/icedteanp/java/sun/applet/PluginStreamHandler.java	Tue Jun 01 16:12:06 2010 +0100
+++ b/plugin/icedteanp/java/sun/applet/PluginStreamHandler.java	Tue Jun 01 17:28:35 2010 +0100
@@ -260,7 +260,7 @@
     		privileges = privs.split(",");
     		nextIndex += 2;
     	}
-    	
+
     	// rest
     	for (int i=nextIndex; i < msgComponents.length; i++) {
     		rest += msgComponents[i];
@@ -284,7 +284,7 @@
     				|| rest.contains("JavaScriptFinalize")
     				|| rest.contains("JavaScriptToString")) {
     			
-				finishCallRequest(rest);
+				finishCallRequest("reference " + reference + " " + rest);
     			return;
     		}
 
--- a/plugin/icedteanp/java/sun/applet/VoidPluginCallRequest.java	Tue Jun 01 16:12:06 2010 +0100
+++ b/plugin/icedteanp/java/sun/applet/VoidPluginCallRequest.java	Tue Jun 01 17:28:35 2010 +0100
@@ -39,28 +39,15 @@
 
 
 public class VoidPluginCallRequest extends PluginCallRequest {
-    public VoidPluginCallRequest(String message, String returnString) {
-        super(message, returnString);
-        PluginDebug.debug ("VoidPLUGINCAlL " + message + " " + returnString);
+    public VoidPluginCallRequest(String message, Long reference) {
+        super(message, reference);
+        PluginDebug.debug ("VoidPluginCall " + message);
     }
 
     public void parseReturn(String message) {
     	setDone(true);
     }
     
-    /**
-     * Returns whether the given message is serviceable by this object
-     * 
-     * @param message The message to service
-     * @return boolean indicating if message is serviceable
-     */
-    public boolean serviceable(String message) {
-    	return message.contains("JavaScriptFinalize") ||
-    			message.contains("JavaScriptRemoveMember") ||
-    			message.contains("JavaScriptSetMember") ||
-    			message.contains("JavaScriptSetSlot");
-    }
-    
     public Object getObject() {
     	return null;
     }
--- a/plugin/tests/LiveConnect/common.js	Tue Jun 01 16:12:06 2010 +0100
+++ b/plugin/tests/LiveConnect/common.js	Tue Jun 01 17:28:35 2010 +0100
@@ -66,7 +66,7 @@
             errored = 0;
             document.getElementById("results").innerHTML = "";
             updateTotals();
-        
+       
             try {
                 if (document.getElementById("testForm").jsjget.checked == 1)
                     getMemberTests();
@@ -116,6 +116,7 @@
             document.getElementById("testForm").jjsset.checked = 1;
             document.getElementById("testForm").jjcparam.checked = 1;
             document.getElementById("testForm").jjcrt.checked = 1;
+            document.getElementById("testForm").jjeval.checked = 1;
 
             doTest();
         }