@@ -95,6 +95,9 @@ static String getClassNameURL(SimpleRPCRunnable runnable) {
9595
9696private static void ajaxRequest (final SimpleRPCRunnable runnable ) {
9797String url =runnable .getHttpURL ();
98+ if (url ==null ) {
99+ url ="" ;
100+ }
98101String method =runnable .getHttpMethod ();
99102String serialize =runnable .serialize ();
100103if (method ==null ) {
@@ -331,28 +334,25 @@ protected static boolean checkXSS(String url, String serialize, SimpleRPCRunnabl
331334 * @j2sNative
332335return function () {
333336var g = net.sf.j2s.ajax.SimpleRPCRequest;
334- var hKey = "h" + rnd;
335- if (g.idSet[hKey] != null) {
336- window.clearTimeout (g.idSet[hKey]);
337- delete g.idSet[hKey];
338- }
339- if (window["net"] != null && !net.sf.j2s.ajax.SimpleRPCRequest.cleanUp(oScript)) {
337+ if (!g.cleanUp(script)) {
340338return; // IE, not completed yet
341339}
342- var src = oScript.src;
343- var idx = src.indexOf ("jzn=");
344- var rid = src.substring (idx + 4, src.indexOf ("&", idx));
345- net.sf.j2s.ajax.SimpleRPCRequest.xssNotify (rid, null);
346- if (oScript.onerror != null) { // W3C
347- oScript.onerror = oScript.onload = null;
340+ if (error) {
341+ var src = script.src;
342+ var idx = src.indexOf ("jzn=");
343+ var rid = src.substring (idx + 4, src.indexOf ("&", idx));
344+ net.sf.j2s.ajax.SimpleRPCRequest.xssNotify (rid, null);
345+ }
346+ if (script.onerror != null) { // W3C
347+ script.onerror = script.onload = null;
348348} else { // IE
349- oScript .onreadystatechange = null;
349+ script .onreadystatechange = null;
350350}
351- document.getElementsByTagName ("HEAD")[0].removeChild (oScript );
352- oScript = null;
351+ document.getElementsByTagName ("HEAD")[0].removeChild (script );
352+ script = null;
353353};
354354 */
355- native static Object generateCallback4Script (Object oScript ,String rnd );
355+ native static Object generateCallback4Script (Object script ,String rnd , boolean error );
356356
357357/**
358358 * @j2sNative
@@ -368,19 +368,28 @@ protected static boolean checkXSS(String url, String serialize, SimpleRPCRunnabl
368368script.type = "text/javascript";
369369script.src = url + "?jzn=" + rnd + "&jzp=" + length
370370+ "&jzc=" + (i + 1) + "&jzz=" + content;
371- var fun = g.generateCallback4Script (script, rnd);
371+ var okFun = g.generateCallback4Script (script, rnd, false);
372+ var errFun = g.generateCallback4Script (script, rnd, true);
372373var userAgent = navigator.userAgent.toLowerCase ();
373374var isOpera = (userAgent.indexOf ("opera") != -1);
374375var isIE = (userAgent.indexOf ("msie") != -1) && !isOpera;
375376script.defer = true;
376377if (typeof (script.onreadystatechange) == "undefined" || !isIE) { // W3C
377- script.onerror = script.onload = fun;
378- } else { // IE
379- script.onreadystatechange = fun;
378+ script.onerror = errFun;
379+ script.onload = okFun;
380+ } else { // IE, IE won't detect script loading error until timeout!
381+ script.onreadystatechange = okFun;
380382}
381383var head = document.getElementsByTagName ("HEAD")[0];
382384head.appendChild (script);
383- g.idSet["h" + rnd] = window.setTimeout (fun, 30000); // 30s timeout // TODO: Expose to configuration
385+ var timeout = 30000;
386+ if (window["j2s.ajax.reqeust.timeout"] != null) {
387+ timeout = window["j2s.ajax.reqeust.timeout"];
388+ }
389+ if (timeout < 1000) {
390+ timeout = 1000; // at least 1s for timeout
391+ }
392+ g.idSet["h" + rnd] = window.setTimeout (errFun, timeout);
384393 */
385394native static void callByScript (String rnd ,String length ,String i ,String content );
386395
@@ -409,11 +418,17 @@ static void xssNotify(String nameID, String response, String session) {
409418var ss = document.getElementsByTagName ("SCRIPT");
410419for (var i = 0; i < ss.length; i++) {
411420var s = ss[i];
412- if (s.src != null && s.src.indexOf ("jzn=" + nameID) != -1
421+ if (s.src != null && s.src.indexOf ("jzn=" + nameID) != -1 // FIXME: Not totally safe
413422&& s.readyState == "interactive") {
414423 s.onreadystatechange = net.sf.j2s.ajax.SimpleRPCRequest.ieScriptCleanup;
415424 }
416425}
426+ }
427+ var hKey = "h" + nameID;
428+ var g = net.sf.j2s.ajax.SimpleRPCRequest;
429+ if (g.idSet[hKey] != null) {
430+ window.clearTimeout (g.idSet[hKey]);
431+ delete g.idSet[hKey];
417432}
418433 */ { }
419434if (response =="continue" ) {
@@ -425,16 +440,27 @@ static void xssNotify(String nameID, String response, String session) {
425440}
426441var k = "x" + nameID;
427442var xcontent = g.idSet[k];
428- // TODO: The following codes should be modified to send out requests one by one.
429443if (xcontent != null) {
444+ // Send out requests one by one.
430445for (var i = 0; i < xcontent.length; i++) {
431446if (xcontent[i] != null) {
432447g.callByScript(nameID, xcontent.length, i, xcontent[i]);
433448xcontent[i] = null;
449+ break;
434450}
435- }
436- g.idSet[k] = null;
437- delete g.idSet[k];
451+ }
452+
453+ var more = false;
454+ for (var i = xcontent.length - 1; i >= 0; i--) {
455+ if (xcontent[i] != null) {
456+ more = true;
457+ break;
458+ }
459+ }
460+ if (!more) { // all contents are sent
461+ g.idSet[k] = null;
462+ delete g.idSet[k];
463+ }
438464}
439465 */ {}
440466return ;