Skip to content

Commit 9fc9ce3

Browse files
author
zhourenjian
committed
Refactor to avoid IE 6.0 memory leak.
Tool sIEve ( http://home.wanadoo.nl/jsrosman/ ) is used to detect memory leak.
1 parent 5b1f8ac commit 9fc9ce3

9 files changed

Lines changed: 574 additions & 358 deletions

File tree

sources/net.sf.j2s.ajax/ajaxpipe/net/sf/j2s/ajax/SimplePipeRequest.java

Lines changed: 81 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -338,26 +338,15 @@ public void onLoaded() {
338338
native static void updatePipeByURL(String url);
339339

340340
/**
341-
* Load or send data for pipe using SCRIPT tag.
342-
*
343-
* @param url
344-
*
345341
* @j2sNative
346-
var script = document.createElement ("SCRIPT");
347-
script.type = "text/javascript";
348-
script.src = url;
349-
script.url = url;
350-
var iframeID = arguments[1];
351-
var userAgent = navigator.userAgent.toLowerCase ();
352-
var isOpera = (userAgent.indexOf ("opera") != -1);
353-
var isIE = (userAgent.indexOf ("msie") != -1) && !isOpera;
354-
var fun = function () {
342+
return function () {
355343
if (iframeID != null) {
356344
if (window.parent == null || window.parent["net"] == null) return;
357345
if (!window.parent.net.sf.j2s.ajax.SimpleRPCRequest.cleanUp(this)) {
358346
return; // IE, not completed yet
359347
}
360348
window.parent.net.sf.j2s.ajax.SimplePipeRequest.updatePipeByURL (this.url);
349+
this.url = null;
361350
document.getElementsByTagName ("HEAD")[0].removeChild (this);
362351
var iframe = window.parent.document.getElementById (iframeID);
363352
if (iframe != null) {
@@ -369,13 +358,32 @@ public void onLoaded() {
369358
return; // IE, not completed yet
370359
}
371360
net.sf.j2s.ajax.SimplePipeRequest.updatePipeByURL (this.url);
361+
this.url = null;
372362
document.getElementsByTagName ("HEAD")[0].removeChild (this);
373363
}
374364
};
365+
*/
366+
native static Object generatePipeScriptCallback(String iframeID);
367+
368+
/**
369+
* Load or send data for pipe using SCRIPT tag.
370+
*
371+
* @param url
372+
*
373+
* @j2sNative
374+
var script = document.createElement ("SCRIPT");
375+
script.type = "text/javascript";
376+
script.src = url;
377+
script.url = url;
378+
var iframeID = arguments[1];
379+
var userAgent = navigator.userAgent.toLowerCase ();
380+
var isOpera = (userAgent.indexOf ("opera") != -1);
381+
var isIE = (userAgent.indexOf ("msie") != -1) && !isOpera;
382+
var fun = net.sf.j2s.ajax.SimplePipeRequest.generatePipeScriptCallback (iframeID);
383+
script.defer = true;
375384
if (typeof (script.onreadystatechange) == "undefined" || !isIE) { // W3C
376385
script.onload = script.onerror = fun;
377386
} else { // IE
378-
script.defer = true;
379387
script.onreadystatechange = fun;
380388
}
381389
var head = document.getElementsByTagName ("HEAD")[0];
@@ -412,6 +420,7 @@ public void onLoaded() {
412420
html += "</scr" + "ipt></head><body><script type=\"text/javascript\">\r\n";
413421
if (ClassLoader.isOpera)
414422
html += "window.setTimeout (function () {\r\n";
423+
html += "net = { sf : { j2s : { ajax : { SimplePipeRequest : { generatePipeScriptCallback : " + net.sf.j2s.ajax.SimplePipeRequest.generatePipeScriptCallback + " } } } } };";
415424
html += "(" + net.sf.j2s.ajax.SimplePipeRequest.loadPipeScript + ") (";
416425
html += "\"" + url.replace (/"/g, "\\\"") + "\", \"" + iframeID + "\"";
417426
html += ");\r\n";
@@ -422,6 +431,20 @@ public void onLoaded() {
422431
*/
423432
native static void loadPipeIFrameScript(String url); // for JavaScript only
424433

434+
/**
435+
* @j2sNative
436+
return function () {
437+
var doc = handle.contentWindow.document;
438+
doc.open ();
439+
doc.write (html);
440+
doc.close ();
441+
// To avoid blank title in title bar
442+
document.title = document.title;
443+
handle = null;
444+
};
445+
*/
446+
native static Object generateLazyIframeWriting(Object handle, String html);
447+
425448
/**
426449
* @param handle
427450
* @param html
@@ -441,16 +464,7 @@ public void onLoaded() {
441464
// To avoid blank title in title bar
442465
document.title = document.title;
443466
} catch (e) {
444-
window.setTimeout ((function (handle, html) {
445-
return function () {
446-
var doc = handle.contentWindow.document;
447-
doc.open ();
448-
doc.write (html);
449-
doc.close ();
450-
// To avoid blank title in title bar
451-
document.title = document.title;
452-
};
453-
}) (handle, html), 25);
467+
window.setTimeout (net.sf.j2s.ajax.SimplePipeRequest.generateLazyIframeWriting (handle, html), 25);
454468
}
455469
*/
456470
native static void iframeDocumentWrite(Object handle, String html);
@@ -570,6 +584,7 @@ public void onLoaded() {
570584
var url = runnable.getPipeURL();
571585
spr.pipeIFrameClean (pipeKey, url);
572586
var subdomain = arguments[1];
587+
(function () { // avoiding element reference in closure
573588
var ifr = document.createElement ("IFRAME");
574589
ifr.style.display = "none";
575590
ifr.id = "pipe-" + pipeKey;
@@ -578,6 +593,7 @@ public void onLoaded() {
578593
+ (subdomain == null ? ""
579594
: "&" + spr.FORM_PIPE_DOMAIN + "=" + subdomain);
580595
document.body.appendChild (ifr);
596+
}) ();
581597
var fun = (function (key, pipeURL, created) {
582598
return function () {
583599
var sph = net.sf.j2s.ajax.SimplePipeHelper;
@@ -1027,12 +1043,13 @@ public void run() {
10271043
var oThis = this;
10281044
this.xhrHandle.onreadystatechange = function () {
10291045
if (oThis.xhrHandle == null) {
1046+
oThis = null;
10301047
return;
10311048
}
10321049
var state = oThis.xhrHandle.readyState;
10331050
if (state == 4) {
10341051
var pipeData = oThis.xhrHandle.responseText;
1035-
oThis.xhrHandle.onreadystatechange = function () {};
1052+
oThis.xhrHandle.onreadystatechange = NullObject;
10361053
var pipe = oThis.runnable;
10371054
if (oThis.xhrHandle.status != 200 && pipe != null) {
10381055
oThis.xhrHandle = null;
@@ -1041,6 +1058,7 @@ public void run() {
10411058
pipe.queryFailedRetries++;
10421059
pipe.queryEnded = true;
10431060
}
1061+
oThis = null;
10441062
return;
10451063
}
10461064
pipe.queryFailedRetries = 0; // succeeded
@@ -1051,6 +1069,7 @@ public void run() {
10511069
net.sf.j2s.ajax.SimplePipeRequest.parseReceived (pipeData);
10521070
oThis.runnable = net.sf.j2s.ajax.SimplePipeHelper.getPipe (oThis.key);
10531071
}
1072+
oThis = null;
10541073
}
10551074
};
10561075
};
@@ -1133,7 +1152,7 @@ public void run() {
11331152
p.pipeXHRQuery (p.xhrHandle, method, url, data);
11341153
p.lastXHR = new Date ().getTime ();
11351154
} catch (e) {
1136-
p.xhrHandle.onreadystatechange = function () {};
1155+
p.xhrHandle.onreadystatechange = NullObject;
11371156
p.xhrHandle = null;
11381157
document.domain = p.parentDomain;
11391158
runnable.queryEnded = true;
@@ -1159,35 +1178,48 @@ public void run() {
11591178

11601179
/**
11611180
* @j2sNative
1162-
var curLoc = "" + window.location;
1163-
var existed = false;
1164-
with (window.parent) {
1165-
var iframes = document.getElementsByTagName ("IFRAME");
1166-
for (var i = 0; i < iframes.length; i++) {
1167-
if (iframes[i].src == curLoc) {
1168-
existed = true;
1169-
break;
1181+
try {
1182+
var curLoc = "" + window.location;
1183+
var existed = false;
1184+
with (window.parent) {
1185+
var iframes = document.getElementsByTagName ("IFRAME");
1186+
for (var i = 0; i < iframes.length; i++) {
1187+
if (iframes[i].src == curLoc) {
1188+
existed = true;
1189+
break;
1190+
}
11701191
}
11711192
}
1172-
}
1173-
if (!existed) { // refreshing in Firefox 3.0 will trigger this scenario
1174-
var idx = curLoc.indexOf ("?");
1175-
if (idx != -1) {
1176-
var urlPrefix = curLoc.substring (0, idx);
1177-
var goalURL = null;
1178-
with (window.parent) {
1179-
var iframes = document.getElementsByTagName ("IFRAME");
1180-
for (var i = 0; i < iframes.length; i++) {
1181-
if (iframes[i].src.indexOf (urlPrefix) == 0) {
1182-
goalURL = iframes[i].src;
1183-
break;
1193+
if (!existed) { // refreshing in Firefox 3.0 will trigger this scenario
1194+
var idx = curLoc.indexOf ("?");
1195+
if (idx != -1) {
1196+
var urlPrefix = curLoc.substring (0, idx);
1197+
var goalURL = null;
1198+
with (window.parent) {
1199+
var iframes = document.getElementsByTagName ("IFRAME");
1200+
for (var i = 0; i < iframes.length; i++) {
1201+
if (iframes[i].src.indexOf (urlPrefix) == 0) {
1202+
goalURL = iframes[i].src;
1203+
break;
1204+
}
11841205
}
11851206
}
1186-
}
1187-
if (goalURL != null) {
1188-
window.location.replace (goalURL);
1207+
if (goalURL != null) {
1208+
window.location.replace (goalURL);
1209+
}
11891210
}
11901211
}
1212+
} catch (e) {}
1213+
$$ = $;
1214+
$ = function (s) {
1215+
$$ (s);
1216+
try {
1217+
var length = document.body.childNodes.length;
1218+
for (var i = length - 1; i >= 0; i--) { // remove old SCRIPT elements
1219+
var child = document.body.childNodes[i];
1220+
child.parentNode.removeChild (child);
1221+
}
1222+
} catch (e) {}
11911223
}
11921224
*/
11931225
native static void checkIFrameSrc(); // for JavaScript only

sources/net.sf.j2s.ajax/ajaxrpc/net/sf/j2s/ajax/SimpleRPCRequest.java

Lines changed: 41 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,33 @@ protected static boolean checkXSS(String url, String serialize, SimpleRPCRunnabl
327327
*/
328328
native static boolean cleanUp(Object scriptObj); // for JavaScript only
329329

330+
/**
331+
* @j2sNative
332+
return function () {
333+
var 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)) {
340+
return; // IE, not completed yet
341+
}
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;
348+
} else { // IE
349+
oScript.onreadystatechange = null;
350+
}
351+
document.getElementsByTagName ("HEAD")[0].removeChild (oScript);
352+
oScript = null;
353+
};
354+
*/
355+
native static Object generateCallback4Script(Object oScript, String rnd);
356+
330357
/**
331358
* @j2sNative
332359
var g = net.sf.j2s.ajax.SimpleRPCRequest;
@@ -341,44 +368,32 @@ protected static boolean checkXSS(String url, String serialize, SimpleRPCRunnabl
341368
script.type = "text/javascript";
342369
script.src = url + "?jzn=" + rnd + "&jzp=" + length
343370
+ "&jzc=" + (i + 1) + "&jzz=" + content;
344-
var fun = (function (oScript) {
345-
return function () {
346-
var g = net.sf.j2s.ajax.SimpleRPCRequest;
347-
var hKey = "h" + rnd;
348-
if (g.idSet[hKey] != null) {
349-
window.clearTimeout (g.idSet[hKey]);
350-
delete g.idSet[hKey];
351-
}
352-
if (window["net"] != null && !net.sf.j2s.ajax.SimpleRPCRequest.cleanUp(oScript)) {
353-
return; // IE, not completed yet
354-
}
355-
var src = oScript.src;
356-
var idx = src.indexOf ("jzn=");
357-
var rid = src.substring (idx + 4, src.indexOf ("&", idx));
358-
net.sf.j2s.ajax.SimpleRPCRequest.xssNotify (rid, null);
359-
if (oScript.onerror != null) { // W3C
360-
oScript.onerror = oScript.onload = null;
361-
} else { // IE
362-
oScript.onreadystatechange = null;
363-
}
364-
document.getElementsByTagName ("HEAD")[0].removeChild (oScript);
365-
};
366-
}) (script);
371+
var fun = g.generateCallback4Script (script, rnd);
367372
var userAgent = navigator.userAgent.toLowerCase ();
368373
var isOpera = (userAgent.indexOf ("opera") != -1);
369374
var isIE = (userAgent.indexOf ("msie") != -1) && !isOpera;
375+
script.defer = true;
370376
if (typeof (script.onreadystatechange) == "undefined" || !isIE) { // W3C
371377
script.onerror = script.onload = fun;
372378
} else { // IE
373-
script.defer = true;
374379
script.onreadystatechange = fun;
375380
}
376381
var head = document.getElementsByTagName ("HEAD")[0];
377382
head.appendChild (script);
378383
g.idSet["h" + rnd] = window.setTimeout (fun, 30000); // 30s timeout // TODO: Expose to configuration
379384
*/
380385
native static void callByScript(String rnd, String length, String i, String content);
381-
386+
387+
/**
388+
* @j2sNative
389+
var state = "" + this.readyState;
390+
if (state == "loaded" || state == "complete") {
391+
this.onreadystatechange = null;
392+
document.getElementsByTagName ("HEAD")[0].removeChild (this);
393+
}
394+
*/
395+
native static void ieScriptCleanup();
396+
382397
/**
383398
* Cross site script notify. Only make senses for JavaScript.
384399
*
@@ -396,13 +411,7 @@ static void xssNotify(String nameID, String response, String session) {
396411
var s = ss[i];
397412
if (s.src != null && s.src.indexOf ("jzn=" + nameID) != -1
398413
&& s.readyState == "interactive") {
399-
s.onreadystatechange = function () {
400-
var state = "" + this.readyState;
401-
if (state == "loaded" || state == "complete") {
402-
this.onreadystatechange = null;
403-
document.getElementsByTagName ("HEAD")[0].removeChild (this);
404-
}
405-
};
414+
s.onreadystatechange = net.sf.j2s.ajax.SimpleRPCRequest.ieScriptCleanup;
406415
}
407416
}
408417
}

sources/net.sf.j2s.ajax/j2sajax/HttpRequest.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@ c$.prototype.registerOnReadyStateChange = function (handler) {
4141
handler.onReceiving ();
4242
} else if (state == 4) {
4343
handler.onLoaded ();
44-
transport.onreadystatechange = function () {};
44+
transport.onreadystatechange = NullObject; // function () {};
45+
transport = null;
4546
}
4647
}
4748
};
@@ -102,7 +103,7 @@ c$.prototype.send = function (str) {
102103
this.transport.send (str);
103104
} catch (e) {
104105
// may be cross-domains exceptions
105-
this.transport.onreadystatechange = function () {};
106+
this.transport.onreadystatechange = NullObject; // function () {};
106107
if (this.xssErrorHandler != null) {
107108
this.xssErrorHandler.onLoaded ();
108109
}

sources/net.sf.j2s.ajax/store/net/sf/j2s/store/XSSCookieStore.java

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,7 @@ public XSSCookieStore(String url) {
4242
if (xssIfr != null) {
4343
return;
4444
}
45-
window.xssCookieReadyCallback = function () {
46-
net.sf.j2s.store.XSSCookieStore.initialized = true;
47-
};
45+
net.sf.j2s.store.XSSCookieStore.initializeCallback ();
4846
var xssIfr = document.createElement ("IFRAME");
4947
xssIfr.id = "xss-cookie";
5048
xssIfr.src = url;
@@ -55,6 +53,16 @@ private static void initialize(String url) {
5553

5654
}
5755

56+
/**
57+
* @j2sNative
58+
window.xssCookieReadyCallback = function () {
59+
net.sf.j2s.store.XSSCookieStore.initialized = true;
60+
};
61+
*/
62+
static void initializeCallback() {
63+
64+
}
65+
5866
/**
5967
* @j2sNative
6068
if (!net.sf.j2s.store.XSSCookieStore.initialized) {

0 commit comments

Comments
 (0)