diff options
author | Benjamin Jones <bjones@galois.com> | 2012-09-27 12:49:34 -0700 |
---|---|---|
committer | Benjamin Jones <bjones@galois.com> | 2012-09-27 15:12:48 -0700 |
commit | 599b9ac75de5d4868b6ea390460d4dbe6784f06e (patch) | |
tree | c049deaae840a7365eacdeb90d3089d78ecb184c /contexts/data/lib/closure-library/closure/goog/net | |
parent | c1b9103d298842b30e0c7e0481a803b217c0e837 (diff) |
updated Google closure library to 9-27-2012 SVN trunk
Diffstat (limited to 'contexts/data/lib/closure-library/closure/goog/net')
201 files changed, 3614 insertions, 28370 deletions
diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/all-wcprops b/contexts/data/lib/closure-library/closure/goog/net/.svn/all-wcprops deleted file mode 100644 index 1c7eccb..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/all-wcprops +++ /dev/null @@ -1,377 +0,0 @@ -K 25 -svn:wc:ra_dav:version-url -V 41 -/svn/!svn/ver/1477/trunk/closure/goog/net -END -ipaddress_test.html -K 25 -svn:wc:ra_dav:version-url -V 61 -/svn/!svn/ver/1274/trunk/closure/goog/net/ipaddress_test.html -END -iframeio_different_base_test.data -K 25 -svn:wc:ra_dav:version-url -V 74 -/svn/!svn/ver/850/trunk/closure/goog/net/iframeio_different_base_test.data -END -networktester_test.html -K 25 -svn:wc:ra_dav:version-url -V 64 -/svn/!svn/ver/850/trunk/closure/goog/net/networktester_test.html -END -imageloader.js -K 25 -svn:wc:ra_dav:version-url -V 56 -/svn/!svn/ver/1472/trunk/closure/goog/net/imageloader.js -END -tmpnetwork.js -K 25 -svn:wc:ra_dav:version-url -V 54 -/svn/!svn/ver/850/trunk/closure/goog/net/tmpnetwork.js -END -bulkloader_test.html -K 25 -svn:wc:ra_dav:version-url -V 61 -/svn/!svn/ver/850/trunk/closure/goog/net/bulkloader_test.html -END -browsertestchannel.js -K 25 -svn:wc:ra_dav:version-url -V 63 -/svn/!svn/ver/1388/trunk/closure/goog/net/browsertestchannel.js -END -ipaddress.js -K 25 -svn:wc:ra_dav:version-url -V 54 -/svn/!svn/ver/1302/trunk/closure/goog/net/ipaddress.js -END -xhrlite.js -K 25 -svn:wc:ra_dav:version-url -V 52 -/svn/!svn/ver/1336/trunk/closure/goog/net/xhrlite.js -END -networktester.js -K 25 -svn:wc:ra_dav:version-url -V 57 -/svn/!svn/ver/850/trunk/closure/goog/net/networktester.js -END -mockxhrlite_test.html -K 25 -svn:wc:ra_dav:version-url -V 62 -/svn/!svn/ver/850/trunk/closure/goog/net/mockxhrlite_test.html -END -channelrequest.js -K 25 -svn:wc:ra_dav:version-url -V 59 -/svn/!svn/ver/1397/trunk/closure/goog/net/channelrequest.js -END -iframeio_test.html -K 25 -svn:wc:ra_dav:version-url -V 60 -/svn/!svn/ver/1153/trunk/closure/goog/net/iframeio_test.html -END -httpstatus.js -K 25 -svn:wc:ra_dav:version-url -V 55 -/svn/!svn/ver/1439/trunk/closure/goog/net/httpstatus.js -END -bulkloader.js -K 25 -svn:wc:ra_dav:version-url -V 55 -/svn/!svn/ver/1302/trunk/closure/goog/net/bulkloader.js -END -filedownloader_test.html -K 25 -svn:wc:ra_dav:version-url -V 66 -/svn/!svn/ver/1434/trunk/closure/goog/net/filedownloader_test.html -END -xmlhttpfactory.js -K 25 -svn:wc:ra_dav:version-url -V 58 -/svn/!svn/ver/850/trunk/closure/goog/net/xmlhttpfactory.js -END -wrapperxmlhttpfactory.js -K 25 -svn:wc:ra_dav:version-url -V 66 -/svn/!svn/ver/1302/trunk/closure/goog/net/wrapperxmlhttpfactory.js -END -iframe_xhr_test_response.html -K 25 -svn:wc:ra_dav:version-url -V 70 -/svn/!svn/ver/850/trunk/closure/goog/net/iframe_xhr_test_response.html -END -xhrio.js -K 25 -svn:wc:ra_dav:version-url -V 50 -/svn/!svn/ver/1453/trunk/closure/goog/net/xhrio.js -END -jsonp.js -K 25 -svn:wc:ra_dav:version-url -V 50 -/svn/!svn/ver/1452/trunk/closure/goog/net/jsonp.js -END -crossdomainrpc_test_response.html -K 25 -svn:wc:ra_dav:version-url -V 74 -/svn/!svn/ver/850/trunk/closure/goog/net/crossdomainrpc_test_response.html -END -filedownloader.js -K 25 -svn:wc:ra_dav:version-url -V 59 -/svn/!svn/ver/1302/trunk/closure/goog/net/filedownloader.js -END -iframeloadmonitor_test_frame3.html -K 25 -svn:wc:ra_dav:version-url -V 75 -/svn/!svn/ver/850/trunk/closure/goog/net/iframeloadmonitor_test_frame3.html -END -imageloader_test.html -K 25 -svn:wc:ra_dav:version-url -V 62 -/svn/!svn/ver/850/trunk/closure/goog/net/imageloader_test.html -END -xmlhttp.js -K 25 -svn:wc:ra_dav:version-url -V 52 -/svn/!svn/ver/1472/trunk/closure/goog/net/xmlhttp.js -END -browserchannel_test.html -K 25 -svn:wc:ra_dav:version-url -V 66 -/svn/!svn/ver/1243/trunk/closure/goog/net/browserchannel_test.html -END -jsloader.js -K 25 -svn:wc:ra_dav:version-url -V 53 -/svn/!svn/ver/1452/trunk/closure/goog/net/jsloader.js -END -mockiframeio.js -K 25 -svn:wc:ra_dav:version-url -V 56 -/svn/!svn/ver/850/trunk/closure/goog/net/mockiframeio.js -END -xhrlite_test.html -K 25 -svn:wc:ra_dav:version-url -V 59 -/svn/!svn/ver/1472/trunk/closure/goog/net/xhrlite_test.html -END -channelrequest_test.html -K 25 -svn:wc:ra_dav:version-url -V 66 -/svn/!svn/ver/1383/trunk/closure/goog/net/channelrequest_test.html -END -xhrlitepool.js -K 25 -svn:wc:ra_dav:version-url -V 55 -/svn/!svn/ver/850/trunk/closure/goog/net/xhrlitepool.js -END -iframeloadmonitor.js -K 25 -svn:wc:ra_dav:version-url -V 62 -/svn/!svn/ver/1302/trunk/closure/goog/net/iframeloadmonitor.js -END -iframe_xhr_test.html -K 25 -svn:wc:ra_dav:version-url -V 62 -/svn/!svn/ver/1395/trunk/closure/goog/net/iframe_xhr_test.html -END -iframeloadmonitor_test_frame.html -K 25 -svn:wc:ra_dav:version-url -V 74 -/svn/!svn/ver/850/trunk/closure/goog/net/iframeloadmonitor_test_frame.html -END -browserchannel.js -K 25 -svn:wc:ra_dav:version-url -V 59 -/svn/!svn/ver/1399/trunk/closure/goog/net/browserchannel.js -END -crossdomainrpc_test.html -K 25 -svn:wc:ra_dav:version-url -V 65 -/svn/!svn/ver/850/trunk/closure/goog/net/crossdomainrpc_test.html -END -multiiframeloadmonitor_test.html -K 25 -svn:wc:ra_dav:version-url -V 73 -/svn/!svn/ver/850/trunk/closure/goog/net/multiiframeloadmonitor_test.html -END -websocket_test.html -K 25 -svn:wc:ra_dav:version-url -V 60 -/svn/!svn/ver/973/trunk/closure/goog/net/websocket_test.html -END -crossdomainrpc_test.gif -K 25 -svn:wc:ra_dav:version-url -V 64 -/svn/!svn/ver/850/trunk/closure/goog/net/crossdomainrpc_test.gif -END -imageloader_testimg1.gif -K 25 -svn:wc:ra_dav:version-url -V 65 -/svn/!svn/ver/850/trunk/closure/goog/net/imageloader_testimg1.gif -END -channeldebug.js -K 25 -svn:wc:ra_dav:version-url -V 57 -/svn/!svn/ver/1248/trunk/closure/goog/net/channeldebug.js -END -imageloader_testimg2.gif -K 25 -svn:wc:ra_dav:version-url -V 65 -/svn/!svn/ver/850/trunk/closure/goog/net/imageloader_testimg2.gif -END -xhrio_test.html -K 25 -svn:wc:ra_dav:version-url -V 57 -/svn/!svn/ver/1472/trunk/closure/goog/net/xhrio_test.html -END -jsonp_test.html -K 25 -svn:wc:ra_dav:version-url -V 57 -/svn/!svn/ver/1452/trunk/closure/goog/net/jsonp_test.html -END -imageloader_testimg3.gif -K 25 -svn:wc:ra_dav:version-url -V 65 -/svn/!svn/ver/850/trunk/closure/goog/net/imageloader_testimg3.gif -END -eventtype.js -K 25 -svn:wc:ra_dav:version-url -V 53 -/svn/!svn/ver/850/trunk/closure/goog/net/eventtype.js -END -xhriopool.js -K 25 -svn:wc:ra_dav:version-url -V 53 -/svn/!svn/ver/850/trunk/closure/goog/net/xhriopool.js -END -cookies_test.html -K 25 -svn:wc:ra_dav:version-url -V 58 -/svn/!svn/ver/850/trunk/closure/goog/net/cookies_test.html -END -bulkloaderhelper.js -K 25 -svn:wc:ra_dav:version-url -V 61 -/svn/!svn/ver/1302/trunk/closure/goog/net/bulkloaderhelper.js -END -errorcode.js -K 25 -svn:wc:ra_dav:version-url -V 53 -/svn/!svn/ver/850/trunk/closure/goog/net/errorcode.js -END -crossdomainrpc.js -K 25 -svn:wc:ra_dav:version-url -V 58 -/svn/!svn/ver/850/trunk/closure/goog/net/crossdomainrpc.js -END -multiiframeloadmonitor.js -K 25 -svn:wc:ra_dav:version-url -V 66 -/svn/!svn/ver/850/trunk/closure/goog/net/multiiframeloadmonitor.js -END -websocket.js -K 25 -svn:wc:ra_dav:version-url -V 54 -/svn/!svn/ver/1302/trunk/closure/goog/net/websocket.js -END -mockxhrlite.js -K 25 -svn:wc:ra_dav:version-url -V 55 -/svn/!svn/ver/850/trunk/closure/goog/net/mockxhrlite.js -END -jsloader_test.html -K 25 -svn:wc:ra_dav:version-url -V 60 -/svn/!svn/ver/1452/trunk/closure/goog/net/jsloader_test.html -END -iframeio.js -K 25 -svn:wc:ra_dav:version-url -V 53 -/svn/!svn/ver/1395/trunk/closure/goog/net/iframeio.js -END -xhrmanager.js -K 25 -svn:wc:ra_dav:version-url -V 55 -/svn/!svn/ver/1302/trunk/closure/goog/net/xhrmanager.js -END -cookies.js -K 25 -svn:wc:ra_dav:version-url -V 52 -/svn/!svn/ver/1472/trunk/closure/goog/net/cookies.js -END -iframeloadmonitor_test_frame2.html -K 25 -svn:wc:ra_dav:version-url -V 75 -/svn/!svn/ver/850/trunk/closure/goog/net/iframeloadmonitor_test_frame2.html -END -iframeio_different_base_test.html -K 25 -svn:wc:ra_dav:version-url -V 74 -/svn/!svn/ver/850/trunk/closure/goog/net/iframeio_different_base_test.html -END -iframeloadmonitor_test.html -K 25 -svn:wc:ra_dav:version-url -V 68 -/svn/!svn/ver/850/trunk/closure/goog/net/iframeloadmonitor_test.html -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/entries b/contexts/data/lib/closure-library/closure/goog/net/.svn/entries deleted file mode 100644 index 0ab3b50..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/entries +++ /dev/null @@ -1,2142 +0,0 @@ -10 - -dir -1494 -http://closure-library.googlecode.com/svn/trunk/closure/goog/net -http://closure-library.googlecode.com/svn - - - -2011-12-14T19:06:32.000000Z -1477 -dpb@google.com - - - - - - - - - - - - - - -0b95b8e8-c90f-11de-9d4f-f947ee5921c8 - -networktester_test.html -file - - - - -2011-12-23T22:42:30.456355Z -4ecefadd766d973571160a3c29c2388e -2011-04-12T20:35:47.000000Z -850 -diegosalas@google.com -has-props - - - - - - - - - - - - - - - - - - - - -6339 - -tmpnetwork.js -file - - - - -2011-12-23T22:42:30.456355Z -542171368a78a90f6f9062ff7784fa68 -2011-04-12T20:35:47.000000Z -850 -diegosalas@google.com -has-props - - - - - - - - - - - - - - - - - - - - -4437 - -bulkloader_test.html -file - - - - -2011-12-23T22:42:30.456355Z -8a3b0fb36fc0c41e25a9c43510aeda56 -2011-04-12T20:35:47.000000Z -850 -diegosalas@google.com -has-props - - - - - - - - - - - - - - - - - - - - -6818 - -xhrlite.js -file - - - - -2011-12-23T22:42:30.457355Z -4760395c844d0649641c2808c3517c1a -2011-10-13T12:17:51.000000Z -1336 -johnmaguire@google.com -has-props - - - - - - - - - - - - - - - - - - - - -4025 - -channelrequest.js -file - - - - -2011-12-23T22:42:30.457355Z -ed8732e66369b4a2e33377bfd660a8cb -2011-11-16T19:24:51.000000Z -1397 -nicksantos@google.com -has-props - - - - - - - - - - - - - - - - - - - - -32535 - -httpstatus.js -file - - - - -2011-12-23T22:42:30.457355Z -cb2cc9f29d2c7c1421f1f1518e98e4c7 -2011-12-01T01:21:24.000000Z -1439 -pupius@google.com -has-props - - - - - - - - - - - - - - - - - - - - -2948 - -wrapperxmlhttpfactory.js -file - - - - -2011-12-23T22:42:30.458355Z -795053f68d1d3fbc0163841db0b1822d -2011-09-27T00:20:47.000000Z -1302 -bmccann@google.com -has-props - - - - - - - - - - - - - - - - - - - - -2106 - -jsloader.js -file - - - - -2011-12-23T22:42:30.458355Z -e338acf3ed58a29d4229c7c3c087aaed -2011-12-07T06:16:31.000000Z -1452 -ebixon@google.com -has-props - - - - - - - - - - - - - - - - - - - - -11979 - -browserchannel_test.html -file - - - - -2011-12-23T22:42:30.458355Z -e979f20ee082710309d0f1a0d89da2cf -2011-08-23T18:48:07.000000Z -1243 -simonmorris@google.com -has-props - - - - - - - - - - - - - - - - - - - - -34344 - -channelrequest_test.html -file - - - - -2011-12-23T22:42:30.458355Z -e9bd16c117f91c9bb6926360be6a4a2d -2011-11-10T21:29:44.000000Z -1383 -nicksantos@google.com -has-props - - - - - - - - - - - - - - - - - - - - -4759 - -xhrlitepool.js -file - - - - -2011-12-23T22:42:30.459355Z -263edc15ca614d02034fd244e166b2ca -2011-04-12T20:35:47.000000Z -850 -diegosalas@google.com -has-props - - - - - - - - - - - - - - - - - - - - -1270 - -iframeloadmonitor_test_frame.html -file - - - - -2011-12-23T22:42:30.459355Z -f84f71085657c4d7599d457ae11285fd -2011-04-12T20:35:47.000000Z -850 -diegosalas@google.com -has-props - - - - - - - - - - - - - - - - - - - - -291 - -crossdomainrpc_test.html -file - - - - -2011-12-23T22:42:30.459355Z -c400f40c7380acf2b91db0eff69b4c9e -2011-04-12T20:35:47.000000Z -850 -diegosalas@google.com -has-props - - - - - - - - - - - - - - - - - - - - -3614 - -imageloader_testimg1.gif -file - - - - -2011-12-23T22:42:30.459355Z -6119f80160fe51207a3d1a834dae1521 -2011-04-12T20:35:47.000000Z -850 -diegosalas@google.com -has-props - - - - - - - - - - - - - - - - - - - - -453 - -imageloader_testimg2.gif -file - - - - -2011-12-23T22:42:30.460355Z -8fbb2a44c7a791c7f0c75f7a62304794 -2011-04-12T20:35:47.000000Z -850 -diegosalas@google.com -has-props - - - - - - - - - - - - - - - - - - - - -460 - -imageloader_testimg3.gif -file - - - - -2011-12-23T22:42:30.460355Z -9da7bb8b5861dd6201a3731dbf8a0a81 -2011-04-12T20:35:47.000000Z -850 -diegosalas@google.com -has-props - - - - - - - - - - - - - - - - - - - - -13446 - -eventtype.js -file - - - - -2011-12-23T22:42:30.460355Z -3f6a7fb6e31a966bc436d1473086bac0 -2011-04-12T20:35:47.000000Z -850 -diegosalas@google.com -has-props - - - - - - - - - - - - - - - - - - - - -1044 - -bulkloaderhelper.js -file - - - - -2011-12-23T22:42:30.460355Z -8775a73d7fd8d446fc0b6b3fdc43aed4 -2011-09-27T00:20:47.000000Z -1302 -bmccann@google.com -has-props - - - - - - - - - - - - - - - - - - - - -3086 - -crossdomainrpc.js -file - - - - -2011-12-23T22:42:30.461355Z -e435e51bdc94da0f18b059c5995f66a7 -2011-04-12T20:35:47.000000Z -850 -diegosalas@google.com -has-props - - - - - - - - - - - - - - - - - - - - -28252 - -mockxhrlite.js -file - - - - -2011-12-23T22:42:30.461355Z -ca57ee5fc3df8104b8355e7ef344d2ed -2011-04-12T20:35:47.000000Z -850 -diegosalas@google.com -has-props - - - - - - - - - - - - - - - - - - - - -1132 - -cookies.js -file - - - - -2011-12-23T22:42:30.461355Z -d987e75fc6e7e38d2ad4a79e39d09bf2 -2011-12-13T22:20:28.000000Z -1472 -ccalabro@google.com -has-props - - - - - - - - - - - - - - - - - - - - -11764 - -xhrmanager.js -file - - - - -2011-12-23T22:42:30.462355Z -d79ad2a0b2b2abe8e0d9da05dc0096d0 -2011-09-27T00:20:47.000000Z -1302 -bmccann@google.com -has-props - - - - - - - - - - - - - - - - - - - - -22053 - -testdata -dir - -iframeloadmonitor_test_frame2.html -file - - - - -2011-12-23T22:42:30.462355Z -3eba82bc5a6ccd7f5e87d1bdc3bb1c53 -2011-04-12T20:35:47.000000Z -850 -diegosalas@google.com -has-props - - - - - - - - - - - - - - - - - - - - -291 - -iframeloadmonitor_test.html -file - - - - -2011-12-23T22:42:30.462355Z -d55b1ca2bc1046b3ed13bbb2ac108aa9 -2011-04-12T20:35:47.000000Z -850 -diegosalas@google.com -has-props - - - - - - - - - - - - - - - - - - - - -3527 - -iframeio_different_base_test.html -file - - - - -2011-12-23T22:42:30.462355Z -927b7f4b542f75ca474528aa0de969d6 -2011-04-12T20:35:47.000000Z -850 -diegosalas@google.com -has-props - - - - - - - - - - - - - - - - - - - - -1279 - -ipaddress_test.html -file - - - - -2011-12-23T22:42:30.463355Z -d731702f1635a28fccb4e0c6acc9014c -2011-09-08T20:28:27.000000Z -1274 -stephenamar@google.com -has-props - - - - - - - - - - - - - - - - - - - - -11044 - -iframeio_different_base_test.data -file - - - - -2011-12-23T22:42:30.463355Z -45b1968f90df42f6624e643e5a6ac9a3 -2011-04-12T20:35:47.000000Z -850 -diegosalas@google.com - - - - - - - - - - - - - - - - - - - - - -86 - -imageloader.js -file - - - - -2011-12-23T22:42:30.463355Z -65a78d12cbcd32c8e46e0517f1ba5952 -2011-12-13T22:20:28.000000Z -1472 -ccalabro@google.com -has-props - - - - - - - - - - - - - - - - - - - - -7765 - -browsertestchannel.js -file - - - - -2011-12-23T22:42:30.463355Z -2960ef9da9220b04d280ab9c08ea54ba -2011-11-14T23:15:47.000000Z -1388 -nicksantos@google.com -has-props - - - - - - - - - - - - - - - - - - - - -17028 - -ipaddress.js -file - - - - -2011-12-23T22:42:30.464355Z -c4abaf630c126ffbea802cf852853e2d -2011-09-27T00:20:47.000000Z -1302 -bmccann@google.com -has-props - - - - - - - - - - - - - - - - - - - - -13512 - -xpc -dir - -networktester.js -file - - - - -2011-12-23T22:42:30.464355Z -17002db90240d3778a3bbc6cfdc2b03a -2011-04-12T20:35:47.000000Z -850 -diegosalas@google.com -has-props - - - - - - - - - - - - - - - - - - - - -9202 - -mockxhrlite_test.html -file - - - - -2011-12-23T22:42:30.464355Z -680360477f2de6cdf86795c25b45c9a6 -2011-04-12T20:35:47.000000Z -850 -diegosalas@google.com -has-props - - - - - - - - - - - - - - - - - - - - -3043 - -iframeio_test.html -file - - - - -2011-12-23T22:42:30.465355Z -8e09e00c7973e6004313a2a6a9126c3e -2011-07-25T16:50:22.000000Z -1153 -lascap@google.com -has-props - - - - - - - - - - - - - - - - - - - - -10090 - -bulkloader.js -file - - - - -2011-12-23T22:42:30.465355Z -04d889a068ab9e8d7b2ceffbbda4f7b3 -2011-09-27T00:20:47.000000Z -1302 -bmccann@google.com -has-props - - - - - - - - - - - - - - - - - - - - -4640 - -filedownloader_test.html -file - - - - -2011-12-23T22:42:30.466355Z -75bed46174a9b474fb370218b73e97a7 -2011-11-30T22:16:21.000000Z -1434 -chrishenry@google.com -has-props - - - - - - - - - - - - - - - - - - - - -12389 - -xmlhttpfactory.js -file - - - - -2011-12-23T22:42:30.466355Z -9fcf54b3e17afe0b1c392e37b329f130 -2011-04-12T20:35:47.000000Z -850 -diegosalas@google.com -has-props - - - - - - - - - - - - - - - - - - - - -1842 - -jsonp.js -file - - - - -2011-12-23T22:42:30.467355Z -5cea1d3600a09558415feab3802549a1 -2011-12-07T06:16:31.000000Z -1452 -ebixon@google.com -has-props - - - - - - - - - - - - - - - - - - - - -11742 - -xhrio.js -file - - - - -2011-12-23T22:42:30.466355Z -7bd0dbd7d39211f7dd6d1d18a83dbcbd -2011-12-07T18:41:01.000000Z -1453 -pupius@google.com -has-props - - - - - - - - - - - - - - - - - - - - -33881 - -iframe_xhr_test_response.html -file - - - - -2011-12-23T22:42:30.466355Z -14aee16432a233f82344ea9740fe16ea -2011-04-12T20:35:47.000000Z -850 -diegosalas@google.com -has-props - - - - - - - - - - - - - - - - - - - - -563 - -crossdomainrpc_test_response.html -file - - - - -2011-12-23T22:42:30.467355Z -563f2a5d32dca8e707c25df1f9501022 -2011-04-12T20:35:47.000000Z -850 -diegosalas@google.com -has-props - - - - - - - - - - - - - - - - - - - - -1653 - -filedownloader.js -file - - - - -2011-12-23T22:42:30.467355Z -2537e091e219598f22b5503a7982222b -2011-09-27T00:20:47.000000Z -1302 -bmccann@google.com -has-props - - - - - - - - - - - - - - - - - - - - -24465 - -iframeloadmonitor_test_frame3.html -file - - - - -2011-12-23T22:42:30.467355Z -c5514b0bcd134b1c241da3e66f813810 -2011-04-12T20:35:47.000000Z -850 -diegosalas@google.com -has-props - - - - - - - - - - - - - - - - - - - - -291 - -xmlhttp.js -file - - - - -2011-12-23T22:42:30.468355Z -e2011c59dc81f5e1ce06586ea64aad79 -2011-12-13T22:20:28.000000Z -1472 -ccalabro@google.com -has-props - - - - - - - - - - - - - - - - - - - - -6393 - -imageloader_test.html -file - - - - -2011-12-23T22:42:30.468355Z -1d7c8649ed23babc8fcc9445505198ea -2011-04-12T20:35:47.000000Z -850 -diegosalas@google.com -has-props - - - - - - - - - - - - - - - - - - - - -6070 - -mockiframeio.js -file - - - - -2011-12-23T22:42:30.468355Z -db53b4b779ecd5c69c990ec1b43421a7 -2011-04-12T20:35:47.000000Z -850 -diegosalas@google.com -has-props - - - - - - - - - - - - - - - - - - - - -8164 - -xhrlite_test.html -file - - - - -2011-12-23T22:42:30.469355Z -5b9f3be7ce15a166e6cc2a37e7a86356 -2011-12-13T22:20:28.000000Z -1472 -ccalabro@google.com -has-props - - - - - - - - - - - - - - - - - - - - -3536 - -iframe_xhr_test.html -file - - - - -2011-12-23T22:42:30.469355Z -f983379fa75cf6d8ff35d1abecd6cc23 -2011-11-16T01:24:53.000000Z -1395 -pupius@google.com -has-props - - - - - - - - - - - - - - - - - - - - -4904 - -iframeloadmonitor.js -file - - - - -2011-12-23T22:42:30.469355Z -d7e3b4e11030fb98977b2fb8ddf9bb29 -2011-09-27T00:20:47.000000Z -1302 -bmccann@google.com -has-props - - - - - - - - - - - - - - - - - - - - -6257 - -browserchannel.js -file - - - - -2011-12-23T22:42:30.469355Z -44969868e3ac1fe2739fe7f3672d8fc7 -2011-11-16T20:03:43.000000Z -1399 -nicksantos@google.com -has-props - - - - - - - - - - - - - - - - - - - - -73966 - -websocket_test.html -file - - - - -2011-12-23T22:42:30.470355Z -f6af5c79039cdab3b4d15350ffcdcb44 -2011-05-26T22:24:22.000000Z -973 -jdeyerle@google.com -has-props - - - - - - - - - - - - - - - - - - - - -11142 - -multiiframeloadmonitor_test.html -file - - - - -2011-12-23T22:42:30.470355Z -bbf798350c87097f6cb8f627ebbe2cb2 -2011-04-12T20:35:47.000000Z -850 -diegosalas@google.com -has-props - - - - - - - - - - - - - - - - - - - - -5666 - -crossdomainrpc_test.gif -file - - - - -2011-12-23T22:42:30.470355Z -d41d8cd98f00b204e9800998ecf8427e -2011-04-12T20:35:47.000000Z -850 -diegosalas@google.com -has-props - - - - - - - - - - - - - - - - - - - - -0 - -channeldebug.js -file - - - - -2011-12-23T22:42:30.470355Z -135fa037c095ab8bb1d8a3a714c5c127 -2011-08-25T15:58:34.000000Z -1248 -bmccann@google.com -has-props - - - - - - - - - - - - - - - - - - - - -7941 - -jsonp_test.html -file - - - - -2011-12-23T22:42:30.471355Z -c68f8cb1703093bf09d737cab9d7b5d3 -2011-12-07T06:16:31.000000Z -1452 -ebixon@google.com -has-props - - - - - - - - - - - - - - - - - - - - -9876 - -xhrio_test.html -file - - - - -2011-12-23T22:42:30.471355Z -491d1d3dffa7ab2df1b87496cc90f676 -2011-12-13T22:20:28.000000Z -1472 -ccalabro@google.com -has-props - - - - - - - - - - - - - - - - - - - - -16693 - -cookies_test.html -file - - - - -2011-12-23T22:42:30.471355Z -5c14dff27acfd7018aad825dfced6ee4 -2011-04-12T20:35:47.000000Z -850 -diegosalas@google.com -has-props - - - - - - - - - - - - - - - - - - - - -6881 - -xhriopool.js -file - - - - -2011-12-23T22:42:30.471355Z -4c9ed5b346ea732e2594b86854fbac9a -2011-04-12T20:35:47.000000Z -850 -diegosalas@google.com -has-props - - - - - - - - - - - - - - - - - - - - -2735 - -errorcode.js -file - - - - -2011-12-23T22:42:30.472355Z -121b2f4c92930d792f997276d8cd5487 -2011-04-12T20:35:47.000000Z -850 -diegosalas@google.com -has-props - - - - - - - - - - - - - - - - - - - - -3287 - -websocket.js -file - - - - -2011-12-23T22:42:30.472355Z -2845b3f2dfb94bb51689fdc4ad79b99c -2011-09-27T00:20:47.000000Z -1302 -bmccann@google.com -has-props - - - - - - - - - - - - - - - - - - - - -15360 - -multiiframeloadmonitor.js -file - - - - -2011-12-23T22:42:30.472355Z -9b8d3191cd9bbc2c1a419c1c7c552654 -2011-04-12T20:35:47.000000Z -850 -diegosalas@google.com -has-props - - - - - - - - - - - - - - - - - - - - -4093 - -jsloader_test.html -file - - - - -2011-12-23T22:42:30.473355Z -61f32714d8b3735fc1c71fdeca6c8827 -2011-12-07T06:16:31.000000Z -1452 -ebixon@google.com -has-props - - - - - - - - - - - - - - - - - - - - -3658 - -iframeio.js -file - - - - -2011-12-23T22:42:30.473355Z -b6fbb54a967bc5224eaca896068db1f7 -2011-11-16T01:24:53.000000Z -1395 -pupius@google.com -has-props - - - - - - - - - - - - - - - - - - - - -39041 - diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/browserchannel.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/browserchannel.js.svn-base deleted file mode 100644 index 530636b..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/browserchannel.js.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 15 -text/javascript -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/browserchannel_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/browserchannel_test.html.svn-base deleted file mode 100644 index d356868..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/browserchannel_test.html.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 9 -text/html -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/browsertestchannel.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/browsertestchannel.js.svn-base deleted file mode 100644 index 530636b..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/browsertestchannel.js.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 15 -text/javascript -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/bulkloader.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/bulkloader.js.svn-base deleted file mode 100644 index 530636b..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/bulkloader.js.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 15 -text/javascript -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/bulkloader_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/bulkloader_test.html.svn-base deleted file mode 100644 index d356868..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/bulkloader_test.html.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 9 -text/html -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/bulkloaderhelper.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/bulkloaderhelper.js.svn-base deleted file mode 100644 index 530636b..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/bulkloaderhelper.js.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 15 -text/javascript -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/channeldebug.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/channeldebug.js.svn-base deleted file mode 100644 index 530636b..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/channeldebug.js.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 15 -text/javascript -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/channelrequest.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/channelrequest.js.svn-base deleted file mode 100644 index 530636b..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/channelrequest.js.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 15 -text/javascript -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/channelrequest_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/channelrequest_test.html.svn-base deleted file mode 100644 index d356868..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/channelrequest_test.html.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 9 -text/html -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/cookies.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/cookies.js.svn-base deleted file mode 100644 index 530636b..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/cookies.js.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 15 -text/javascript -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/cookies_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/cookies_test.html.svn-base deleted file mode 100644 index d356868..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/cookies_test.html.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 9 -text/html -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/crossdomainrpc.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/crossdomainrpc.js.svn-base deleted file mode 100644 index 530636b..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/crossdomainrpc.js.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 15 -text/javascript -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/crossdomainrpc_test.gif.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/crossdomainrpc_test.gif.svn-base deleted file mode 100644 index 1c48e39..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/crossdomainrpc_test.gif.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 9 -image/gif -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/crossdomainrpc_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/crossdomainrpc_test.html.svn-base deleted file mode 100644 index d356868..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/crossdomainrpc_test.html.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 9 -text/html -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/crossdomainrpc_test_response.html.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/crossdomainrpc_test_response.html.svn-base deleted file mode 100644 index d356868..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/crossdomainrpc_test_response.html.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 9 -text/html -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/errorcode.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/errorcode.js.svn-base deleted file mode 100644 index 530636b..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/errorcode.js.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 15 -text/javascript -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/eventtype.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/eventtype.js.svn-base deleted file mode 100644 index 530636b..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/eventtype.js.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 15 -text/javascript -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/filedownloader.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/filedownloader.js.svn-base deleted file mode 100644 index 530636b..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/filedownloader.js.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 15 -text/javascript -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/filedownloader_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/filedownloader_test.html.svn-base deleted file mode 100644 index d356868..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/filedownloader_test.html.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 9 -text/html -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/httpstatus.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/httpstatus.js.svn-base deleted file mode 100644 index 931becf..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/httpstatus.js.svn-base +++ /dev/null @@ -1,9 +0,0 @@ -K 14 -svn:executable -V 1 -* -K 13 -svn:mime-type -V 15 -text/javascript -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/iframe_xhr_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/iframe_xhr_test.html.svn-base deleted file mode 100644 index d356868..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/iframe_xhr_test.html.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 9 -text/html -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/iframe_xhr_test_response.html.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/iframe_xhr_test_response.html.svn-base deleted file mode 100644 index d356868..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/iframe_xhr_test_response.html.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 9 -text/html -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/iframeio.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/iframeio.js.svn-base deleted file mode 100644 index 530636b..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/iframeio.js.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 15 -text/javascript -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/iframeio_different_base_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/iframeio_different_base_test.html.svn-base deleted file mode 100644 index d356868..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/iframeio_different_base_test.html.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 9 -text/html -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/iframeio_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/iframeio_test.html.svn-base deleted file mode 100644 index d356868..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/iframeio_test.html.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 9 -text/html -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/iframeloadmonitor.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/iframeloadmonitor.js.svn-base deleted file mode 100644 index 530636b..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/iframeloadmonitor.js.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 15 -text/javascript -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/iframeloadmonitor_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/iframeloadmonitor_test.html.svn-base deleted file mode 100644 index d356868..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/iframeloadmonitor_test.html.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 9 -text/html -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/iframeloadmonitor_test_frame.html.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/iframeloadmonitor_test_frame.html.svn-base deleted file mode 100644 index d356868..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/iframeloadmonitor_test_frame.html.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 9 -text/html -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/iframeloadmonitor_test_frame2.html.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/iframeloadmonitor_test_frame2.html.svn-base deleted file mode 100644 index d356868..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/iframeloadmonitor_test_frame2.html.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 9 -text/html -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/iframeloadmonitor_test_frame3.html.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/iframeloadmonitor_test_frame3.html.svn-base deleted file mode 100644 index d356868..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/iframeloadmonitor_test_frame3.html.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 9 -text/html -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/imageloader.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/imageloader.js.svn-base deleted file mode 100644 index 530636b..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/imageloader.js.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 15 -text/javascript -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/imageloader_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/imageloader_test.html.svn-base deleted file mode 100644 index d356868..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/imageloader_test.html.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 9 -text/html -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/imageloader_testimg1.gif.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/imageloader_testimg1.gif.svn-base deleted file mode 100644 index 1c48e39..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/imageloader_testimg1.gif.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 9 -image/gif -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/imageloader_testimg2.gif.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/imageloader_testimg2.gif.svn-base deleted file mode 100644 index 1c48e39..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/imageloader_testimg2.gif.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 9 -image/gif -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/imageloader_testimg3.gif.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/imageloader_testimg3.gif.svn-base deleted file mode 100644 index 1c48e39..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/imageloader_testimg3.gif.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 9 -image/gif -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/ipaddress.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/ipaddress.js.svn-base deleted file mode 100644 index 530636b..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/ipaddress.js.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 15 -text/javascript -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/ipaddress_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/ipaddress_test.html.svn-base deleted file mode 100644 index d356868..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/ipaddress_test.html.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 9 -text/html -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/jsloader.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/jsloader.js.svn-base deleted file mode 100644 index 530636b..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/jsloader.js.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 15 -text/javascript -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/jsloader_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/jsloader_test.html.svn-base deleted file mode 100644 index d356868..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/jsloader_test.html.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 9 -text/html -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/jsonp.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/jsonp.js.svn-base deleted file mode 100644 index 530636b..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/jsonp.js.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 15 -text/javascript -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/jsonp_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/jsonp_test.html.svn-base deleted file mode 100644 index d356868..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/jsonp_test.html.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 9 -text/html -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/mockiframeio.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/mockiframeio.js.svn-base deleted file mode 100644 index 530636b..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/mockiframeio.js.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 15 -text/javascript -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/mockxhrlite.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/mockxhrlite.js.svn-base deleted file mode 100644 index 530636b..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/mockxhrlite.js.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 15 -text/javascript -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/mockxhrlite_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/mockxhrlite_test.html.svn-base deleted file mode 100644 index d356868..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/mockxhrlite_test.html.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 9 -text/html -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/multiiframeloadmonitor.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/multiiframeloadmonitor.js.svn-base deleted file mode 100644 index 530636b..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/multiiframeloadmonitor.js.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 15 -text/javascript -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/multiiframeloadmonitor_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/multiiframeloadmonitor_test.html.svn-base deleted file mode 100644 index d356868..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/multiiframeloadmonitor_test.html.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 9 -text/html -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/networktester.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/networktester.js.svn-base deleted file mode 100644 index 530636b..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/networktester.js.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 15 -text/javascript -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/networktester_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/networktester_test.html.svn-base deleted file mode 100644 index d356868..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/networktester_test.html.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 9 -text/html -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/tmpnetwork.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/tmpnetwork.js.svn-base deleted file mode 100644 index 530636b..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/tmpnetwork.js.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 15 -text/javascript -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/websocket.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/websocket.js.svn-base deleted file mode 100644 index 530636b..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/websocket.js.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 15 -text/javascript -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/websocket_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/websocket_test.html.svn-base deleted file mode 100644 index d356868..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/websocket_test.html.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 9 -text/html -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/wrapperxmlhttpfactory.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/wrapperxmlhttpfactory.js.svn-base deleted file mode 100644 index 530636b..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/wrapperxmlhttpfactory.js.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 15 -text/javascript -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/xhrio.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/xhrio.js.svn-base deleted file mode 100644 index 530636b..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/xhrio.js.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 15 -text/javascript -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/xhrio_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/xhrio_test.html.svn-base deleted file mode 100644 index d356868..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/xhrio_test.html.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 9 -text/html -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/xhriopool.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/xhriopool.js.svn-base deleted file mode 100644 index 530636b..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/xhriopool.js.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 15 -text/javascript -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/xhrlite.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/xhrlite.js.svn-base deleted file mode 100644 index 530636b..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/xhrlite.js.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 15 -text/javascript -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/xhrlite_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/xhrlite_test.html.svn-base deleted file mode 100644 index d356868..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/xhrlite_test.html.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 9 -text/html -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/xhrlitepool.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/xhrlitepool.js.svn-base deleted file mode 100644 index 530636b..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/xhrlitepool.js.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 15 -text/javascript -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/xhrmanager.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/xhrmanager.js.svn-base deleted file mode 100644 index 530636b..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/xhrmanager.js.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 15 -text/javascript -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/xmlhttp.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/xmlhttp.js.svn-base deleted file mode 100644 index 530636b..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/xmlhttp.js.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 15 -text/javascript -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/xmlhttpfactory.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/xmlhttpfactory.js.svn-base deleted file mode 100644 index 530636b..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/prop-base/xmlhttpfactory.js.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 15 -text/javascript -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/browserchannel.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/browserchannel.js.svn-base deleted file mode 100644 index fbfef88..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/browserchannel.js.svn-base +++ /dev/null @@ -1,2470 +0,0 @@ -// Copyright 2006 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Definition of the BrowserChannel class. A BrowserChannel - * simulates a bidirectional socket over HTTP. It is the basis of the - * Gmail Chat IM connections to the server. - * - * See http://wiki/Main/BrowserChannel - * This doesn't yet completely comform to the design document as we've done - * some renaming and cleanup in the design document that hasn't yet been - * implemented in the protocol. - * - * Typical usage will look like - * var handler = [handler object]; - * var channel = new BrowserChannel(clientVersion); - * channel.setHandler(handler); - * channel.connect('channel/test', 'channel/bind'); - * - * See goog.net.BrowserChannel.Handler for the handler interface. - * - */ - - -goog.provide('goog.net.BrowserChannel'); -goog.provide('goog.net.BrowserChannel.Error'); -goog.provide('goog.net.BrowserChannel.Event'); -goog.provide('goog.net.BrowserChannel.Handler'); -goog.provide('goog.net.BrowserChannel.LogSaver'); -goog.provide('goog.net.BrowserChannel.QueuedMap'); -goog.provide('goog.net.BrowserChannel.Stat'); -goog.provide('goog.net.BrowserChannel.StatEvent'); -goog.provide('goog.net.BrowserChannel.State'); -goog.provide('goog.net.BrowserChannel.TimingEvent'); - -goog.require('goog.Uri'); -goog.require('goog.array'); -goog.require('goog.debug.Logger'); -goog.require('goog.debug.TextFormatter'); -goog.require('goog.events.Event'); -goog.require('goog.events.EventTarget'); -goog.require('goog.json'); -goog.require('goog.net.BrowserTestChannel'); -goog.require('goog.net.ChannelDebug'); -goog.require('goog.net.ChannelRequest'); -goog.require('goog.net.ChannelRequest.Error'); -goog.require('goog.net.XhrIo'); -goog.require('goog.net.tmpnetwork'); -goog.require('goog.string'); -goog.require('goog.structs'); -goog.require('goog.structs.CircularBuffer'); -goog.require('goog.userAgent'); - - - -/** - * Encapsulates the logic for a single BrowserChannel. - * - * @param {string} clientVersion An application-specific version number that - * is sent to the server when connected. - * @constructor - */ -goog.net.BrowserChannel = function(clientVersion) { - /** - * The application specific version that is passed to the server. - * @type {string} - * @private - */ - this.clientVersion_ = clientVersion; - - /** - * The current state of the BrowserChannel. It should be one of the - * goog.net.BrowserChannel.State constants. - * @type {goog.net.BrowserChannel.State} - * @private - */ - this.state_ = goog.net.BrowserChannel.State.INIT; - - /** - * An array of queued maps that need to be sent to the server. - * @type {Array.<goog.net.BrowserChannel.QueuedMap>} - * @private - */ - this.outgoingMaps_ = []; - - /** - * An array of dequeued maps that we have either received a non-successful - * response for, or no response at all, and which therefore may or may not - * have been received by the server. - * @type {Array.<goog.net.BrowserChannel.QueuedMap>} - * @private - */ - this.pendingMaps_ = []; - - /** - * The channel debug used for browserchannel logging - * @type {goog.net.ChannelDebug} - * @private - */ - this.channelDebug_ = new goog.net.ChannelDebug(); -}; - - - -/** - * Simple container class for a (mapId, map) pair. - * @param {number} mapId The id for this map. - * @param {Object|goog.structs.Map} map The map itself. - * @constructor - */ -goog.net.BrowserChannel.QueuedMap = function(mapId, map) { - /** - * The id for this map. - * @type {number} - */ - this.mapId = mapId; - - /** - * The map itself. - * @type {Object|goog.structs.Map} - */ - this.map = map; -}; - - -/** - * Extra HTTP headers to add to all the requests sent to the server. - * @type {Object} - * @private - */ -goog.net.BrowserChannel.prototype.extraHeaders_ = null; - - -/** - * Extra parameters to add to all the requests sent to the server. - * @type {Object} - * @private - */ -goog.net.BrowserChannel.prototype.extraParams_ = null; - - -/** - * The current ChannelRequest object for the forwardchannel. - * @type {goog.net.ChannelRequest?} - * @private - */ -goog.net.BrowserChannel.prototype.forwardChannelRequest_ = null; - - -/** - * The ChannelRequest object for the backchannel. - * @type {goog.net.ChannelRequest?} - * @private - */ -goog.net.BrowserChannel.prototype.backChannelRequest_ = null; - - -/** - * The relative path (in the context of the the page hosting the browser - * channel) for making requests to the server. - * @type {?string} - * @private - */ -goog.net.BrowserChannel.prototype.path_ = null; - - -/** - * The absolute URI for the forwardchannel request. - * @type {goog.Uri} - * @private - */ -goog.net.BrowserChannel.prototype.forwardChannelUri_ = null; - - -/** - * The absolute URI for the backchannel request. - * @type {goog.Uri} - * @private - */ -goog.net.BrowserChannel.prototype.backChannelUri_ = null; - - -/** - * A subdomain prefix for using a subdomain in IE for the backchannel - * requests. - * @type {?string} - * @private - */ -goog.net.BrowserChannel.prototype.hostPrefix_ = null; - - -/** - * Whether we allow the use of a subdomain in IE for the backchannel requests. - * @private - */ -goog.net.BrowserChannel.prototype.allowHostPrefix_ = true; - - -/** - * The next id to use for the RID (request identifier) parameter. This - * identifier uniquely identifies the forward channel request. - * @type {number} - * @private - */ -goog.net.BrowserChannel.prototype.nextRid_ = 0; - - -/** - * The id to use for the next outgoing map. This identifier uniquely - * identifies a sent map. - * @type {number} - * @private - */ -goog.net.BrowserChannel.prototype.nextMapId_ = 0; - - -/** - * Whether to fail forward-channel requests after one try, or after a few tries. - * @type {boolean} - * @private - */ -goog.net.BrowserChannel.prototype.failFast_ = false; - - -/** - * The handler that receive callbacks for state changes and data. - * @type {goog.net.BrowserChannel.Handler} - * @private - */ -goog.net.BrowserChannel.prototype.handler_ = null; - - -/** - * Timer identifier for asynchronously making a forward channel request. - * @type {?number} - * @private - */ -goog.net.BrowserChannel.prototype.forwardChannelTimerId_ = null; - - -/** - * Timer identifier for asynchronously making a back channel request. - * @type {?number} - * @private - */ -goog.net.BrowserChannel.prototype.backChannelTimerId_ = null; - - -/** - * Timer identifier for the timer that waits for us to retry the backchannel in - * the case where it is dead and no longer receiving data. - * @type {?number} - * @private - */ -goog.net.BrowserChannel.prototype.deadBackChannelTimerId_ = null; - - -/** - * The BrowserTestChannel object which encapsulates the logic for determining - * interesting network conditions about the client. - * @type {goog.net.BrowserTestChannel?} - * @private - */ -goog.net.BrowserChannel.prototype.connectionTest_ = null; - - -/** - * Whether the client's network conditions can support chunked responses. - * @type {?boolean} - * @private - */ -goog.net.BrowserChannel.prototype.useChunked_ = null; - - -/** - * Whether chunked mode is allowed. In certain debugging situations, it's - * useful to disable this. - * @private - */ -goog.net.BrowserChannel.prototype.allowChunkedMode_ = true; - - -/** - * The array identifier of the last array received from the server for the - * backchannel request. - * @type {number} - * @private - */ -goog.net.BrowserChannel.prototype.lastArrayId_ = -1; - - -/** - * The array identifier of the last array sent by the server that we know about. - * @type {number} - * @private - */ -goog.net.BrowserChannel.prototype.lastPostResponseArrayId_ = -1; - - -/** - * The last status code received. - * @type {number} - * @private - */ -goog.net.BrowserChannel.prototype.lastStatusCode_ = -1; - - -/** - * Number of times we have retried the current forward channel request. - * @type {number} - * @private - */ -goog.net.BrowserChannel.prototype.forwardChannelRetryCount_ = 0; - - -/** - * Number of times it a row that we have retried the current back channel - * request and received no data. - * @type {number} - * @private - */ -goog.net.BrowserChannel.prototype.backChannelRetryCount_ = 0; - - -/** - * The attempt id for the current back channel request. Starts at 1 and - * increments for each reconnect. The server uses this to log if our connection - * is flaky or not. - * @type {number} - * @private - */ -goog.net.BrowserChannel.prototype.backChannelAttemptId_; - - -/** - * The latest protocol version that this class supports. We request this version - * from the server when opening the connection. Should match - * com.google.net.browserchannel.BrowserChannel.LATEST_CHANNEL_VERSION. - * @type {number} - */ -goog.net.BrowserChannel.LATEST_CHANNEL_VERSION = 8; - - -/** - * The channel version that we negotiated with the server for this session. - * Starts out as the version we request, and then is changed to the negotiated - * version after the initial open. - * @type {number} - * @private - */ -goog.net.BrowserChannel.prototype.channelVersion_ = - goog.net.BrowserChannel.LATEST_CHANNEL_VERSION; - - -/** - * Enum type for the browser channel state machine. - * @enum {number} - */ -goog.net.BrowserChannel.State = { - /** The channel is closed. */ - CLOSED: 0, - - /** The channel has been initialized but hasn't yet initiated a connection. */ - INIT: 1, - - /** The channel is in the process of opening a connection to the server. */ - OPENING: 2, - - /** The channel is open. */ - OPENED: 3 -}; - - -/** - * Maximum number of attempts to connect to the server for forward channel - * requests. - * @type {number} - */ -goog.net.BrowserChannel.FORWARD_CHANNEL_MAX_RETRIES = 2; - - -/** - * The timeout in milliseconds for a forward channel request. - * @type {number} - */ -goog.net.BrowserChannel.FORWARD_CHANNEL_RETRY_TIMEOUT = 20 * 1000; - - -/** - * Maximum number of attempts to connect to the server for back channel - * requests. - * @type {number} - */ -goog.net.BrowserChannel.BACK_CHANNEL_MAX_RETRIES = 3; - - -/** - * Default timeout in MS before the initial retry. Subsequent retries will be - * slower. - * @type {number} - */ -goog.net.BrowserChannel.RETRY_DELAY_MS = 5 * 1000; - - -/** - * We will add a random time between 0 and this number of MS to retries to - * the retry time for this request. - * @type {number} - */ -goog.net.BrowserChannel.RETRY_DELAY_SEED = 10 * 1000; - - -/** - * A number in MS of how long we guess the maxmium amount of time a round trip - * to the server should take. In the future this could be substituted with a - * real measurement of the RTT. - * @type {number} - */ -goog.net.BrowserChannel.RTT_ESTIMATE = 3 * 1000; - - -/** - * When retrying for an inactive channel, we will multiply the total delay by - * this number. - * @type {number} - */ -goog.net.BrowserChannel.INACTIVE_CHANNEL_RETRY_FACTOR = 2; - - -/** - * Enum type for identifying a BrowserChannel error. - * @enum {number} - */ -goog.net.BrowserChannel.Error = { - /** Value that indicates no error has occurred. */ - OK: 0, - - /** An error due to a request failing. */ - REQUEST_FAILED: 2, - - /** An error due to the user being logged out. */ - LOGGED_OUT: 4, - - /** An error due to server response which contains no data. */ - NO_DATA: 5, - - /** An error due to a server response indicating an unknown session id */ - UNKNOWN_SESSION_ID: 6, - - /** An error due to a server response requesting to stop the channel. */ - STOP: 7, - - /** A general network error. */ - NETWORK: 8, - - /** An error due to the channel being blocked by a network administrator. */ - BLOCKED: 9, - - /** An error due to bad data being returned from the server. */ - BAD_DATA: 10, - - /** An error due to a response that doesn't start with the magic cookie. */ - BAD_RESPONSE: 11 -}; - - -/** - * Internal enum type for the two browser channel channel types. - * @enum {number} - * @private - */ -goog.net.BrowserChannel.ChannelType_ = { - FORWARD_CHANNEL: 1, - - BACK_CHANNEL: 2 -}; - - -/** - * The maximum number of maps that can be sent in one POST. Should match - * com.google.net.browserchannel.BrowserChannel.MAX_MAPS_PER_REQUEST. - * @type {number} - * @private - */ -goog.net.BrowserChannel.MAX_MAPS_PER_REQUEST_ = 1000; - - -/** - * Singleton event target for firing stat events - * @type {goog.events.EventTarget} - * @private - */ -goog.net.BrowserChannel.statEventTarget_ = new goog.events.EventTarget(); - - -/** - * Events fired by BrowserChannel and associated objects - * @type {Object} - */ -goog.net.BrowserChannel.Event = {}; - - -/** - * Stat Event that fires when things of interest happen that may be useful for - * applications to know about for stats or debugging purposes. This event fires - * on the EventTarget returned by getStatEventTarget. - */ -goog.net.BrowserChannel.Event.STAT_EVENT = 'statevent'; - - - -/** - * Event class for goog.net.BrowserChannel.Event.STAT_EVENT - * - * @param {goog.events.EventTarget} eventTarget The stat event target for - the browser channel. - * @param {goog.net.BrowserChannel.Stat} stat The stat. - * @constructor - * @extends {goog.events.Event} - */ -goog.net.BrowserChannel.StatEvent = function(eventTarget, stat) { - goog.events.Event.call(this, goog.net.BrowserChannel.Event.STAT_EVENT, - eventTarget); - - /** - * The stat - * @type {goog.net.BrowserChannel.Stat} - */ - this.stat = stat; - -}; -goog.inherits(goog.net.BrowserChannel.StatEvent, goog.events.Event); - - -/** - * An event that fires when POST requests complete successfully, indicating - * the size of the POST and the round trip time. - * This event fires on the EventTarget returned by getStatEventTarget. - */ -goog.net.BrowserChannel.Event.TIMING_EVENT = 'timingevent'; - - - -/** - * Event class for goog.net.BrowserChannel.Event.TIMING_EVENT - * - * @param {goog.events.EventTarget} target The stat event target for - the browser channel. - * @param {number} size The number of characters in the POST data. - * @param {number} rtt The total round trip time from POST to response in MS. - * @param {number} retries The number of times the POST had to be retried. - * @constructor - * @extends {goog.events.Event} - */ -goog.net.BrowserChannel.TimingEvent = function(target, size, rtt, retries) { - goog.events.Event.call(this, goog.net.BrowserChannel.Event.TIMING_EVENT, - target); - - /** - * @type {number} - */ - this.size = size; - - /** - * @type {number} - */ - this.rtt = rtt; - - /** - * @type {number} - */ - this.retries = retries; - -}; -goog.inherits(goog.net.BrowserChannel.TimingEvent, goog.events.Event); - - -/** - * Enum that identifies events for statistics that are interesting to track. - * TODO(user) - Change name not to use Event or use EventTarget - * @enum {number} - */ -goog.net.BrowserChannel.Stat = { - /** Event indicating a new connection attempt. */ - CONNECT_ATTEMPT: 0, - - /** Event indicating a connection error due to a general network problem. */ - ERROR_NETWORK: 1, - - /** - * Event indicating a connection error that isn't due to a general network - * problem. - */ - ERROR_OTHER: 2, - - /** Event indicating the start of test stage one. */ - TEST_STAGE_ONE_START: 3, - - - /** Event indicating the channel is blocked by a network administrator. */ - CHANNEL_BLOCKED: 4, - - /** Event indicating the start of test stage two. */ - TEST_STAGE_TWO_START: 5, - - /** Event indicating the first piece of test data was received. */ - TEST_STAGE_TWO_DATA_ONE: 6, - - /** - * Event indicating that the second piece of test data was received and it was - * recieved separately from the first. - */ - TEST_STAGE_TWO_DATA_TWO: 7, - - /** Event indicating both pieces of test data were received simultaneously. */ - TEST_STAGE_TWO_DATA_BOTH: 8, - - /** Event indicating stage one of the test request failed. */ - TEST_STAGE_ONE_FAILED: 9, - - /** Event indicating stage two of the test request failed. */ - TEST_STAGE_TWO_FAILED: 10, - - /** - * Event indicating that a buffering proxy is likely between the client and - * the server. - */ - PROXY: 11, - - /** - * Event indicating that no buffering proxy is likely between the client and - * the server. - */ - NOPROXY: 12, - - /** Event indicating an unknown SID error. */ - REQUEST_UNKNOWN_SESSION_ID: 13, - - /** Event indicating a bad status code was received. */ - REQUEST_BAD_STATUS: 14, - - /** Event indicating incomplete data was received */ - REQUEST_INCOMPLETE_DATA: 15, - - /** Event indicating bad data was received */ - REQUEST_BAD_DATA: 16, - - /** Event indicating no data was received when data was expected. */ - REQUEST_NO_DATA: 17, - - /** Event indicating a request timeout. */ - REQUEST_TIMEOUT: 18, - - /** - * Event indicating that the server never received our hanging GET and so it - * is being retried. - */ - BACKCHANNEL_MISSING: 19, - - /** - * Event indicating that we have determined that our hanging GET is not - * receiving data when it should be. Thus it is dead dead and will be retried. - */ - BACKCHANNEL_DEAD: 20 -}; - - -/** - * The normal response for forward channel requests. - * Used only before version 8 of the protocol. - * @type {string} - */ -goog.net.BrowserChannel.MAGIC_RESPONSE_COOKIE = 'y2f%'; - - -/** - * A guess at a cutoff at which to no longer assume the backchannel is dead - * when we are slow to receive data. Number in bytes. - * - * Assumption: The worst bandwidth we work on is 50 kilobits/sec - * 50kbits/sec * (1 byte / 8 bits) * 6 sec dead backchannel timeout - * @type {number} - */ -goog.net.BrowserChannel.OUTSTANDING_DATA_BACKCHANNEL_RETRY_CUTOFF = 37500; - - -/** - * Returns the browserchannel logger. - * - * @return {goog.net.ChannelDebug} The channel debug object. - */ -goog.net.BrowserChannel.prototype.getChannelDebug = function() { - return this.channelDebug_; -}; - - -/** - * Set the browserchannel logger. - * TODO(user): Add interface for channel loggers or remove this function. - * - * @param {goog.net.ChannelDebug} channelDebug The channel debug object. - */ -goog.net.BrowserChannel.prototype.setChannelDebug = function( - channelDebug) { - this.channelDebug_ = channelDebug; -}; - - -/** - * Allows the application to set an execution hooks for when BrowserChannel - * starts processing requests. This is useful to track timing or logging - * special information. The function takes no parameters and return void. - * @param {Function} startHook The function for the start hook. - */ -goog.net.BrowserChannel.setStartThreadExecutionHook = function(startHook) { - goog.net.BrowserChannel.startExecutionHook_ = startHook; -}; - - -/** - * Allows the application to set an execution hooks for when BrowserChannel - * stops processing requests. This is useful to track timing or logging - * special information. The function takes no parameters and return void. - * @param {Function} endHook The function for the end hook. - */ -goog.net.BrowserChannel.setEndThreadExecutionHook = function(endHook) { - goog.net.BrowserChannel.endExecutionHook_ = endHook; -}; - - -/** - * Application provided execution hook for the start hook. - * - * @type {Function} - * @private - */ -goog.net.BrowserChannel.startExecutionHook_ = function() { }; - - -/** - * Application provided execution hook for the end hook. - * - * @type {Function} - * @private - */ -goog.net.BrowserChannel.endExecutionHook_ = function() { }; - - -/** - * Instantiates a ChannelRequest with the given parameters. Overidden in tests. - * - * @param {goog.net.BrowserChannel|goog.net.BrowserTestChannel} channel - * The BrowserChannel that owns this request. - * @param {goog.net.ChannelDebug} channelDebug A ChannelDebug to use for - * logging. - * @param {string=} opt_sessionId The session id for the channel. - * @param {string|number=} opt_requestId The request id for this request. - * @param {number=} opt_retryId The retry id for this request. - * @return {goog.net.ChannelRequest} The created channel request. - */ -goog.net.BrowserChannel.createChannelRequest = function( - channel, channelDebug, opt_sessionId, opt_requestId, opt_retryId) { - return new goog.net.ChannelRequest( - channel, - channelDebug, - opt_sessionId, - opt_requestId, - opt_retryId); -}; - - -/** - * Starts the channel. This initiates connections to the server. - * - * @param {string} testPath The path for the test connection. - * @param {string} channelPath The path for the channel connection. - * @param {Object} extraParams Extra parameter keys and values to add to the - * requests. - * @param {string=} opt_oldSessionId Session ID from a previous session. - * @param {number=} opt_oldArrayId The last array ID from a previous session. - */ -goog.net.BrowserChannel.prototype.connect = function(testPath, channelPath, - extraParams, opt_oldSessionId, opt_oldArrayId) { - this.channelDebug_.debug('connect()'); - - goog.net.BrowserChannel.notifyStatEvent( - goog.net.BrowserChannel.Stat.CONNECT_ATTEMPT); - - this.path_ = channelPath; - this.extraParams_ = extraParams || {}; - - // Attach parameters about the previous session if reconnecting. - if (opt_oldSessionId && goog.isDef(opt_oldArrayId)) { - this.extraParams_['OSID'] = opt_oldSessionId; - this.extraParams_['OAID'] = opt_oldArrayId; - } - - this.connectTest_(testPath); -}; - - -/** - * Disconnects and closes the channel. - */ -goog.net.BrowserChannel.prototype.disconnect = function() { - this.channelDebug_.debug('disconnect()'); - - this.cancelRequests_(); - - if (this.state_ == goog.net.BrowserChannel.State.OPENED) { - var rid = this.nextRid_++; - var uri = this.forwardChannelUri_.clone(); - uri.setParameterValue('SID', this.sid_); - uri.setParameterValue('RID', rid); - uri.setParameterValue('TYPE', 'terminate'); - - // Add the reconnect parameters. - this.addAdditionalParams_(uri); - - var request = goog.net.BrowserChannel.createChannelRequest( - this, this.channelDebug_, this.sid_, rid); - request.sendUsingImgTag(uri); - this.onClose_(); - } -}; - - -/** - * Returns the session id of the channel. Only available after the - * channel has been opened. - * @return {string} Session ID. - */ -goog.net.BrowserChannel.prototype.getSessionId = function() { - return this.sid_; -}; - - -/** - * Starts the test channel to determine network conditions. - * - * @param {string} testPath The relative PATH for the test connection. - * @private - */ -goog.net.BrowserChannel.prototype.connectTest_ = function(testPath) { - this.channelDebug_.debug('connectTest_()'); - if (!this.okToMakeRequest_()) { - return; // channel is cancelled - } - this.connectionTest_ = new goog.net.BrowserTestChannel( - this, this.channelDebug_); - this.connectionTest_.setExtraHeaders(this.extraHeaders_); - this.connectionTest_.connect(testPath); -}; - - -/** - * Starts the regular channel which is run after the test channel is complete. - * @private - */ -goog.net.BrowserChannel.prototype.connectChannel_ = function() { - this.channelDebug_.debug('connectChannel_()'); - this.ensureInState_(goog.net.BrowserChannel.State.INIT, - goog.net.BrowserChannel.State.CLOSED); - this.forwardChannelUri_ = - this.getForwardChannelUri(/** @type {string} */ (this.path_)); - this.ensureForwardChannel_(); -}; - - -/** - * Cancels all outstanding requests. - * @private - */ -goog.net.BrowserChannel.prototype.cancelRequests_ = function() { - if (this.connectionTest_) { - this.connectionTest_.abort(); - this.connectionTest_ = null; - } - - if (this.backChannelRequest_) { - this.backChannelRequest_.cancel(); - this.backChannelRequest_ = null; - } - - if (this.backChannelTimerId_) { - goog.global.clearTimeout(this.backChannelTimerId_); - this.backChannelTimerId_ = null; - } - - this.clearDeadBackchannelTimer_(); - - if (this.forwardChannelRequest_) { - this.forwardChannelRequest_.cancel(); - this.forwardChannelRequest_ = null; - } - - if (this.forwardChannelTimerId_) { - goog.global.clearTimeout(this.forwardChannelTimerId_); - this.forwardChannelTimerId_ = null; - } -}; - - -/** - * Returns the extra HTTP headers to add to all the requests sent to the server. - * - * @return {Object} The HTTP headers, or null. - */ -goog.net.BrowserChannel.prototype.getExtraHeaders = function() { - return this.extraHeaders_; -}; - - -/** - * Sets extra HTTP headers to add to all the requests sent to the server. - * - * @param {Object} extraHeaders The HTTP headers, or null. - */ -goog.net.BrowserChannel.prototype.setExtraHeaders = function(extraHeaders) { - this.extraHeaders_ = extraHeaders; -}; - - -/** - * Returns the handler used for channel callback events. - * - * @return {goog.net.BrowserChannel.Handler} The handler. - */ -goog.net.BrowserChannel.prototype.getHandler = function() { - return this.handler_; -}; - - -/** - * Sets the handler used for channel callback events. - * @param {goog.net.BrowserChannel.Handler} handler The handler to set. - */ -goog.net.BrowserChannel.prototype.setHandler = function(handler) { - this.handler_ = handler; -}; - - -/** - * Returns whether the channel allows the use of a subdomain. There may be - * cases where this isn't allowed. - * @return {boolean} Whether a host prefix is allowed. - */ -goog.net.BrowserChannel.prototype.getAllowHostPrefix = function() { - return this.allowHostPrefix_; -}; - - -/** - * Sets whether the channel allows the use of a subdomain. There may be cases - * where this isn't allowed, for example, logging in with troutboard where - * using a subdomain causes Apache to force the user to authenticate twice. - * @param {boolean} allowHostPrefix Whether a host prefix is allowed. - */ -goog.net.BrowserChannel.prototype.setAllowHostPrefix = - function(allowHostPrefix) { - this.allowHostPrefix_ = allowHostPrefix; -}; - - -/** - * Returns whether the channel is buffered or not. This state is valid for - * querying only after the test connection has completed. This may be - * queried in the goog.net.BrowserChannel.okToMakeRequest() callback. - * A channel may be buffered if the test connection determines that - * a chunked response could not be sent down within a suitable time. - * @return {boolean} Whether the channel is buffered. - */ -goog.net.BrowserChannel.prototype.isBuffered = function() { - return !this.useChunked_; -}; - - -/** - * Returns whether chunked mode is allowed. In certain debugging situations, - * it's useful for the application to have a way to disable chunked mode for a - * user. - - * @return {boolean} Whether chunked mode is allowed. - */ -goog.net.BrowserChannel.prototype.getAllowChunkedMode = - function() { - return this.allowChunkedMode_; -}; - - -/** - * Sets whether chunked mode is allowed. In certain debugging situations, it's - * useful for the application to have a way to disable chunked mode for a user. - * @param {boolean} allowChunkedMode Whether chunked mode is allowed. - */ -goog.net.BrowserChannel.prototype.setAllowChunkedMode = - function(allowChunkedMode) { - this.allowChunkedMode_ = allowChunkedMode; -}; - - -/** - * Sends a request to the server. The format of the request is a Map data - * structure of key/value pairs. These maps are then encoded in a format - * suitable for the wire and then reconstituted as a Map data structure that - * the server can process. - * @param {Object|goog.structs.Map} map The map to send. - */ -goog.net.BrowserChannel.prototype.sendMap = function(map) { - if (this.state_ == goog.net.BrowserChannel.State.CLOSED) { - throw Error('Invalid operation: sending map when state is closed'); - } - - // We can only send 1000 maps per POST, but typically we should never have - // that much to send, so warn if we exceed that (we still send all the maps). - if (this.outgoingMaps_.length == - goog.net.BrowserChannel.MAX_MAPS_PER_REQUEST_) { - // severe() is temporary so that we get these uploaded and can figure out - // what's causing them. Afterwards can change to warning(). - this.channelDebug_.severe( - 'Already have ' + goog.net.BrowserChannel.MAX_MAPS_PER_REQUEST_ + - ' queued maps upon queueing ' + goog.json.serialize(map)); - } - - this.outgoingMaps_.push( - new goog.net.BrowserChannel.QueuedMap(this.nextMapId_++, map)); - if (this.state_ == goog.net.BrowserChannel.State.OPENING || - this.state_ == goog.net.BrowserChannel.State.OPENED) { - this.ensureForwardChannel_(); - } -}; - - -/** - * When set to true, this changes the behavior of the forward channel so it - * will not retry requests; it will fail after one network failure, and if - * there was already one network failure, the request will fail immediately. - * @param {boolean} failFast Whether or not to fail fast. - */ -goog.net.BrowserChannel.prototype.setFailFast = function(failFast) { - this.failFast_ = failFast; - this.channelDebug_.info('setFailFast: ' + failFast); - if ((this.forwardChannelRequest_ || this.forwardChannelTimerId_) && - this.forwardChannelRetryCount_ > this.getForwardChannelMaxRetries()) { - this.channelDebug_.info( - 'Retry count ' + this.forwardChannelRetryCount_ + - ' > new maxRetries ' + this.getForwardChannelMaxRetries() + - '. Fail immediately!'); - if (this.forwardChannelRequest_) { - this.forwardChannelRequest_.cancel(); - // Go through the standard onRequestComplete logic to expose the max-retry - // failure in the standard way. - this.onRequestComplete(this.forwardChannelRequest_); - } else { // i.e., this.forwardChannelTimerId_ - goog.global.clearTimeout(this.forwardChannelTimerId_); - this.forwardChannelTimerId_ = null; - // The error code from the last failed request is gone, so just use a - // generic one. - this.signalError_(goog.net.BrowserChannel.Error.REQUEST_FAILED); - } - } -}; - - -/** - * @return {number} The max number of forward-channel retries, which will be 0 - * in fail-fast mode. - */ -goog.net.BrowserChannel.prototype.getForwardChannelMaxRetries = function() { - return this.failFast_ ? - 0 : goog.net.BrowserChannel.FORWARD_CHANNEL_MAX_RETRIES; -}; - - -/** - * @return {number} The max number of back-channel retries, which is a constant. - */ -goog.net.BrowserChannel.prototype.getBackChannelMaxRetries = function() { - // Back-channel retries is a constant. - return goog.net.BrowserChannel.BACK_CHANNEL_MAX_RETRIES; -}; - - -/** - * Returns whether the channel is closed - * @return {boolean} true if the channel is closed. - */ -goog.net.BrowserChannel.prototype.isClosed = function() { - return this.state_ == goog.net.BrowserChannel.State.CLOSED; -}; - - -/** - * Returns the browser channel state. - * @return {goog.net.BrowserChannel.State} The current state of the browser - * channel. - */ -goog.net.BrowserChannel.prototype.getState = function() { - return this.state_; -}; - - -/** - * Return the last status code received for a request. - * @return {number} The last status code received for a request. - */ -goog.net.BrowserChannel.prototype.getLastStatusCode = function() { - return this.lastStatusCode_; -}; - - -/** - * @return {number} The last array id received. - */ -goog.net.BrowserChannel.prototype.getLastArrayId = function() { - return this.lastArrayId_; -}; - - -/** - * Returns whether there are outstanding requests servicing the channel. - * @return {boolean} true if there are outstanding requests. - */ -goog.net.BrowserChannel.prototype.hasOutstandingRequests = function() { - return this.outstandingRequests_() != 0; -}; - - -/** - * Returns the number of outstanding requests. - * @return {number} The number of outstanding requests to the server. - * @private - */ -goog.net.BrowserChannel.prototype.outstandingRequests_ = function() { - var count = 0; - if (this.backChannelRequest_) { - count++; - } - if (this.forwardChannelRequest_) { - count++; - } - return count; -}; - - -/** - * Ensures that a forward channel request is scheduled. - * @private - */ -goog.net.BrowserChannel.prototype.ensureForwardChannel_ = function() { - if (this.forwardChannelRequest_) { - // connection in process - no need to start a new request - return; - } - - if (this.forwardChannelTimerId_) { - // no need to start a new request - one is already scheduled - return; - } - - this.forwardChannelTimerId_ = goog.net.BrowserChannel.setTimeout( - goog.bind(this.onStartForwardChannelTimer_, this), 0); - this.forwardChannelRetryCount_ = 0; -}; - - -/** - * Schedules a forward-channel retry for the specified request, unless the max - * retries has been reached. - * @param {goog.net.ChannelRequest} request The failed request to retry. - * @return {boolean} true iff a retry was scheduled. - * @private - */ -goog.net.BrowserChannel.prototype.maybeRetryForwardChannel_ = - function(request) { - if (this.forwardChannelRequest_ || this.forwardChannelTimerId_) { - // Should be impossible to be called in this state. - this.channelDebug_.severe('Request already in progress'); - return false; - } - - if (this.state_ == goog.net.BrowserChannel.State.INIT || // no retry open_() - (this.forwardChannelRetryCount_ >= this.getForwardChannelMaxRetries())) { - return false; - } - - this.channelDebug_.debug('Going to retry POST'); - - this.forwardChannelTimerId_ = goog.net.BrowserChannel.setTimeout( - goog.bind(this.onStartForwardChannelTimer_, this, request), - this.getRetryTime_(this.forwardChannelRetryCount_)); - this.forwardChannelRetryCount_++; - return true; -}; - - -/** - * Timer callback for ensureForwardChannel - * @param {goog.net.ChannelRequest=} opt_retryRequest A failed request to retry. - * @private - */ -goog.net.BrowserChannel.prototype.onStartForwardChannelTimer_ = function( - opt_retryRequest) { - this.forwardChannelTimerId_ = null; - this.startForwardChannel_(opt_retryRequest); -}; - - -/** - * Begins a new forward channel operation to the server. - * @param {goog.net.ChannelRequest=} opt_retryRequest A failed request to retry. - * @private - */ -goog.net.BrowserChannel.prototype.startForwardChannel_ = function( - opt_retryRequest) { - this.channelDebug_.debug('startForwardChannel_'); - if (!this.okToMakeRequest_()) { - return; // channel is cancelled - } else if (this.state_ == goog.net.BrowserChannel.State.INIT) { - if (opt_retryRequest) { - this.channelDebug_.severe('Not supposed to retry the open'); - return; - } - this.open_(); - this.state_ = goog.net.BrowserChannel.State.OPENING; - } else if (this.state_ == goog.net.BrowserChannel.State.OPENED) { - if (opt_retryRequest) { - this.makeForwardChannelRequest_(opt_retryRequest); - return; - } - - if (this.outgoingMaps_.length == 0) { - this.channelDebug_.debug('startForwardChannel_ returned: ' + - 'nothing to send'); - // no need to start a new forward channel request - return; - } - - if (this.forwardChannelRequest_) { - // Should be impossible to be called in this state. - this.channelDebug_.severe('startForwardChannel_ returned: ' + - 'connection already in progress'); - return; - } - - this.makeForwardChannelRequest_(); - this.channelDebug_.debug('startForwardChannel_ finished, sent request'); - } -}; - - -/** - * Establishes a new channel session with the the server. - * @private - */ -goog.net.BrowserChannel.prototype.open_ = function() { - this.channelDebug_.debug('open_()'); - this.nextRid_ = Math.floor(Math.random() * 100000); - - var rid = this.nextRid_++; - var request = goog.net.BrowserChannel.createChannelRequest( - this, this.channelDebug_, '', rid); - request.setExtraHeaders(this.extraHeaders_); - var requestText = this.dequeueOutgoingMaps_(); - var uri = this.forwardChannelUri_.clone(); - uri.setParameterValue('RID', rid); - if (this.clientVersion_) { - uri.setParameterValue('CVER', this.clientVersion_); - } - - // Add the reconnect parameters. - this.addAdditionalParams_(uri); - - request.xmlHttpPost(uri, requestText, true); - this.forwardChannelRequest_ = request; -}; - - -/** - * Makes a forward channel request using XMLHTTP. - * @param {goog.net.ChannelRequest=} opt_retryRequest A failed request to retry. - * @private - */ -goog.net.BrowserChannel.prototype.makeForwardChannelRequest_ = - function(opt_retryRequest) { - var rid; - var requestText; - if (opt_retryRequest) { - if (this.channelVersion_ > 6) { - // In version 7 and up we can tack on new arrays to a retry. - this.requeuePendingMaps_(); - rid = this.nextRid_ - 1; // Must use last RID - requestText = this.dequeueOutgoingMaps_(); - } else { - // TODO(user): Remove this code and the opt_retryRequest passing - // once server-side support for ver 7 is ubiquitous. - rid = opt_retryRequest.getRequestId(); - requestText = /** @type {string} */ (opt_retryRequest.getPostData()); - } - } else { - rid = this.nextRid_++; - requestText = this.dequeueOutgoingMaps_(); - } - - var uri = this.forwardChannelUri_.clone(); - uri.setParameterValue('SID', this.sid_); - uri.setParameterValue('RID', rid); - uri.setParameterValue('AID', this.lastArrayId_); - // Add the additional reconnect parameters. - this.addAdditionalParams_(uri); - - var request = goog.net.BrowserChannel.createChannelRequest( - this, - this.channelDebug_, - this.sid_, - rid, - this.forwardChannelRetryCount_ + 1); - request.setExtraHeaders(this.extraHeaders_); - - // randomize from 50%-100% of the forward channel timeout to avoid - // a big hit if servers happen to die at once. - request.setTimeout( - Math.round(goog.net.BrowserChannel.FORWARD_CHANNEL_RETRY_TIMEOUT * 0.50) + - Math.round(goog.net.BrowserChannel.FORWARD_CHANNEL_RETRY_TIMEOUT * 0.50 * - Math.random())); - this.forwardChannelRequest_ = request; - request.xmlHttpPost(uri, requestText, true); -}; - - -/** - * Adds the additional parameters from the handler to the given URI. - * @param {goog.Uri} uri The URI to add the parameters to. - * @private - */ -goog.net.BrowserChannel.prototype.addAdditionalParams_ = function(uri) { - // Add the additional reconnect parameters as needed. - if (this.handler_) { - var params = this.handler_.getAdditionalParams(this); - if (params) { - goog.structs.forEach(params, function(value, key, coll) { - uri.setParameterValue(key, value); - }); - } - } -}; - - -/** - * Returns the request text from the outgoing maps and resets it. - * @return {string} The encoded request text created from all the currently - * queued outgoing maps. - * @private - */ -goog.net.BrowserChannel.prototype.dequeueOutgoingMaps_ = function() { - var count = Math.min(this.outgoingMaps_.length, - goog.net.BrowserChannel.MAX_MAPS_PER_REQUEST_); - var sb = ['count=' + count]; - var offset; - if (this.channelVersion_ > 6 && count > 0) { - // To save a bit of bandwidth, specify the base mapId and the rest as - // offsets from it. - offset = this.outgoingMaps_[0].mapId; - sb.push('ofs=' + offset); - } else { - offset = 0; - } - for (var i = 0; i < count; i++) { - var mapId = this.outgoingMaps_[i].mapId; - var map = this.outgoingMaps_[i].map; - if (this.channelVersion_ <= 6) { - // Map IDs were not used in ver 6 and before, just indexes in the request. - mapId = i; - } else { - mapId -= offset; - } - try { - goog.structs.forEach(map, function(value, key, coll) { - sb.push('req' + mapId + '_' + key + '=' + encodeURIComponent(value)); - }); - } catch (ex) { - // We send a map here because lots of the retry logic relies on map IDs, - // so we have to send something. - sb.push('req' + mapId + '_' + 'type' + '=' + - encodeURIComponent('_badmap')); - if (this.handler_) { - this.handler_.badMapError(this, map); - } - } - } - this.pendingMaps_ = this.pendingMaps_.concat( - this.outgoingMaps_.splice(0, count)); - return sb.join('&'); -}; - - -/** - * Requeues unacknowledged sent arrays for retransmission in the next forward - * channel request. - * @private - */ -goog.net.BrowserChannel.prototype.requeuePendingMaps_ = function() { - this.outgoingMaps_ = this.pendingMaps_.concat(this.outgoingMaps_); - this.pendingMaps_.length = 0; -}; - - -/** - * Ensures there is a backchannel request for receiving data from the server. - * @private - */ -goog.net.BrowserChannel.prototype.ensureBackChannel_ = function() { - if (this.backChannelRequest_) { - // already have one - return; - } - - if (this.backChannelTimerId_) { - // no need to start a new request - one is already scheduled - return; - } - - this.backChannelAttemptId_ = 1; - this.backChannelTimerId_ = goog.net.BrowserChannel.setTimeout( - goog.bind(this.onStartBackChannelTimer_, this), 0); - this.backChannelRetryCount_ = 0; -}; - - -/** - * Schedules a back-channel retry, unless the max retries has been reached. - * @return {boolean} true iff a retry was scheduled. - * @private - */ -goog.net.BrowserChannel.prototype.maybeRetryBackChannel_ = function() { - if (this.backChannelRequest_ || this.backChannelTimerId_) { - // Should be impossible to be called in this state. - this.channelDebug_.severe('Request already in progress'); - return false; - } - - if (this.backChannelRetryCount_ >= this.getBackChannelMaxRetries()) { - return false; - } - - this.channelDebug_.debug('Going to retry GET'); - - this.backChannelAttemptId_++; - this.backChannelTimerId_ = goog.net.BrowserChannel.setTimeout( - goog.bind(this.onStartBackChannelTimer_, this), - this.getRetryTime_(this.backChannelRetryCount_)); - this.backChannelRetryCount_++; - return true; -}; - - -/** - * Timer callback for ensureBackChannel_. - * @private - */ -goog.net.BrowserChannel.prototype.onStartBackChannelTimer_ = function() { - this.backChannelTimerId_ = null; - this.startBackChannel_(); -}; - - -/** - * Begins a new back channel operation to the server. - * @private - */ -goog.net.BrowserChannel.prototype.startBackChannel_ = function() { - if (!this.okToMakeRequest_()) { - // channel is cancelled - return; - } - - this.channelDebug_.debug('Creating new HttpRequest'); - this.backChannelRequest_ = goog.net.BrowserChannel.createChannelRequest( - this, - this.channelDebug_, - this.sid_, - 'rpc', - this.backChannelAttemptId_); - this.backChannelRequest_.setExtraHeaders(this.extraHeaders_); - var uri = this.backChannelUri_.clone(); - uri.setParameterValue('RID', 'rpc'); - uri.setParameterValue('SID', this.sid_); - uri.setParameterValue('CI', this.useChunked_ ? '0' : '1'); - uri.setParameterValue('AID', this.lastArrayId_); - - // Add the reconnect parameters. - this.addAdditionalParams_(uri); - - if (!goog.net.ChannelRequest.supportsXhrStreaming()) { - uri.setParameterValue('TYPE', 'html'); - this.backChannelRequest_.tridentGet(uri, Boolean(this.hostPrefix_)); - } else { - uri.setParameterValue('TYPE', 'xmlhttp'); - this.backChannelRequest_.xmlHttpGet(uri, true /* decodeChunks */, - this.hostPrefix_, false /* opt_noClose */); - } - this.channelDebug_.debug('New Request created'); -}; - - -/** - * Gives the handler a chance to return an error code and stop channel - * execution. A handler might want to do this to check that the user is still - * logged in, for example. - * @private - * @return {boolean} If it's OK to make a request. - */ -goog.net.BrowserChannel.prototype.okToMakeRequest_ = function() { - if (this.handler_) { - var result = this.handler_.okToMakeRequest(this); - if (result != goog.net.BrowserChannel.Error.OK) { - this.channelDebug_.debug('Handler returned error code from ' + - 'okToMakeRequest'); - this.signalError_(result); - return false; - } - } - return true; -}; - - -/** - * Callback from BrowserTestChannel for when the channel is finished. - * @param {goog.net.BrowserTestChannel} testChannel The BrowserTestChannel. - * @param {boolean} useChunked Whether we can chunk responses. - */ -goog.net.BrowserChannel.prototype.testConnectionFinished = - function(testChannel, useChunked) { - this.channelDebug_.debug('Test Connection Finished'); - - this.useChunked_ = this.allowChunkedMode_ && useChunked; - this.lastStatusCode_ = testChannel.getLastStatusCode(); - this.connectChannel_(); -}; - - -/** - * Callback from BrowserTestChannel for when the channel has an error. - * @param {goog.net.BrowserTestChannel} testChannel The BrowserTestChannel. - * @param {goog.net.ChannelRequest.Error} errorCode The error code of the - failure. - */ -goog.net.BrowserChannel.prototype.testConnectionFailure = - function(testChannel, errorCode) { - this.channelDebug_.debug('Test Connection Failed'); - this.lastStatusCode_ = testChannel.getLastStatusCode(); - this.signalError_(goog.net.BrowserChannel.Error.REQUEST_FAILED); -}; - - -/** - * Callback from BrowserTestChannel for when the channel is blocked. - * @param {goog.net.BrowserTestChannel} testChannel The BrowserTestChannel. - */ -goog.net.BrowserChannel.prototype.testConnectionBlocked = - function(testChannel) { - this.channelDebug_.debug('Test Connection Blocked'); - this.lastStatusCode_ = this.connectionTest_.getLastStatusCode(); - this.signalError_(goog.net.BrowserChannel.Error.BLOCKED); -}; - - -/** - * Callback from ChannelRequest for when new data is received - * @param {goog.net.ChannelRequest} request The request object. - * @param {string} responseText The text of the response. - */ -goog.net.BrowserChannel.prototype.onRequestData = - function(request, responseText) { - if (this.state_ == goog.net.BrowserChannel.State.CLOSED || - (this.backChannelRequest_ != request && - this.forwardChannelRequest_ != request)) { - // either CLOSED or a request we don't know about (perhaps an old request) - return; - } - this.lastStatusCode_ = request.getLastStatusCode(); - - if (this.forwardChannelRequest_ == request && - this.state_ == goog.net.BrowserChannel.State.OPENED) { - if (this.channelVersion_ > 7) { - var response; - try { - response = (/** @type {Array} */ goog.json.unsafeParse(responseText)); - } catch (ex) { - response = null; - } - if (goog.isArray(response) && response.length == 3) { - this.handlePostResponse_(response); - } else { - this.channelDebug_.debug('Bad POST response data returned'); - this.signalError_(goog.net.BrowserChannel.Error.BAD_RESPONSE); - } - } else if (responseText != goog.net.BrowserChannel.MAGIC_RESPONSE_COOKIE) { - this.channelDebug_.debug('Bad data returned - missing/invald ' + - 'magic cookie'); - this.signalError_(goog.net.BrowserChannel.Error.BAD_RESPONSE); - } - } else { - if (this.backChannelRequest_ == request) { - this.clearDeadBackchannelTimer_(); - } - if (!goog.string.isEmpty(responseText)) { - this.onInput_(/** @type {Array} */ (goog.json.unsafeParse(responseText))); - } - } -}; - - -/** - * Handles a POST response from the server. - * @param {Array} responseValues The key value pairs in the POST response. - * @private - */ -goog.net.BrowserChannel.prototype.handlePostResponse_ = function( - responseValues) { - // The first response value is set to 0 if server is missing backchannel. - if (responseValues[0] == 0) { - this.handleBackchannelMissing_(); - return; - } - this.lastPostResponseArrayId_ = responseValues[1]; - var outstandingArrays = this.lastPostResponseArrayId_ - this.lastArrayId_; - if (0 < outstandingArrays) { - var numOutstandingBackchannelBytes = responseValues[2]; - this.channelDebug_.debug(numOutstandingBackchannelBytes + ' bytes (in ' + - outstandingArrays + ' arrays) are outstanding on the BackChannel'); - if (!this.shouldRetryBackChannel_(numOutstandingBackchannelBytes)) { - return; - } - if (!this.deadBackChannelTimerId_) { - // We expect to receive data within 2 RTTs or we retry the backchannel. - this.deadBackChannelTimerId_ = goog.net.BrowserChannel.setTimeout( - goog.bind(this.onBackChannelDead_, this), - 2 * goog.net.BrowserChannel.RTT_ESTIMATE); - } - } -}; - - -/** - * Handles a POST response from the server telling us that it has detected that - * we have no hanging GET connection. - * @private - */ -goog.net.BrowserChannel.prototype.handleBackchannelMissing_ = function() { - // As long as the back channel was started before the POST was sent, - // we should retry the backchannel. We give a slight buffer of RTT_ESTIMATE - // so as not to excessively retry the backchannel - this.channelDebug_.debug('Server claims our backchannel is missing.'); - if (this.backChannelTimerId_) { - this.channelDebug_.debug('But we are currently starting the request.'); - return; - } else if (!this.backChannelRequest_) { - this.channelDebug_.warning( - 'We do not have a BackChannel established'); - } else if (this.backChannelRequest_.getRequestStartTime() + - goog.net.BrowserChannel.RTT_ESTIMATE < - this.forwardChannelRequest_.getRequestStartTime()) { - this.clearDeadBackchannelTimer_(); - this.backChannelRequest_.cancel(); - this.backChannelRequest_ = null; - } else { - return; - } - this.maybeRetryBackChannel_(); - goog.net.BrowserChannel.notifyStatEvent( - goog.net.BrowserChannel.Stat.BACKCHANNEL_MISSING); -}; - - -/** - * Determines whether we should start the process of retrying a possibly - * dead backchannel. - * @param {number} outstandingBytes The number of bytes for which the server has - * not yet received acknowledgement. - * @return {boolean} Whether to start the backchannel retry timer. - * @private - */ -goog.net.BrowserChannel.prototype.shouldRetryBackChannel_ = function( - outstandingBytes) { - // Not too many outstanding bytes, not buffered and not after a retry. - return outstandingBytes < - goog.net.BrowserChannel.OUTSTANDING_DATA_BACKCHANNEL_RETRY_CUTOFF && - !this.isBuffered() && - this.backChannelRetryCount_ == 0; -}; - - -/** - * Decides which host prefix should be used, if any. If there is a handler, - * allows the handler to validate a host prefix provided by the server, and - * optionally override it. - * @param {?string} serverHostPrefix The host prefix provided by the server. - * @return {?string} The host prefix to actually use, if any. Will return null - * if the use of host prefixes was disabled via setAllowHostPrefix(). - */ -goog.net.BrowserChannel.prototype.correctHostPrefix = function( - serverHostPrefix) { - if (this.allowHostPrefix_) { - if (this.handler_) { - return this.handler_.correctHostPrefix(serverHostPrefix); - } - return serverHostPrefix; - } - return null; -}; - - -/** - * Handles the timer that indicates that our backchannel is no longer able to - * successfully receive data from the server. - * @private - */ -goog.net.BrowserChannel.prototype.onBackChannelDead_ = function() { - if (goog.isDefAndNotNull(this.deadBackChannelTimerId_)) { - this.deadBackChannelTimerId_ = null; - this.backChannelRequest_.cancel(); - this.backChannelRequest_ = null; - this.maybeRetryBackChannel_(); - goog.net.BrowserChannel.notifyStatEvent( - goog.net.BrowserChannel.Stat.BACKCHANNEL_DEAD); - } -}; - - -/** - * Clears the timer that indicates that our backchannel is no longer able to - * successfully receive data from the server. - * @private - */ -goog.net.BrowserChannel.prototype.clearDeadBackchannelTimer_ = function() { - if (goog.isDefAndNotNull(this.deadBackChannelTimerId_)) { - goog.global.clearTimeout(this.deadBackChannelTimerId_); - this.deadBackChannelTimerId_ = null; - } -}; - - -/** - * Returns whether or not the given error/status combination is fatal or not. - * On fatal errors we immediately close the session rather than retrying the - * failed request. - * @param {goog.net.ChannelRequest.Error?} error The error code for the failed - * request. - * @param {number} statusCode The last HTTP status code. - * @return {boolean} Whether or not the error is fatal. - * @private - */ -goog.net.BrowserChannel.isFatalError_ = - function(error, statusCode) { - return error == goog.net.ChannelRequest.Error.UNKNOWN_SESSION_ID || - (error == goog.net.ChannelRequest.Error.STATUS && - statusCode > 0); -}; - - -/** - * Callback from ChannelRequest that indicates a request has completed. - * @param {goog.net.ChannelRequest} request The request object. - */ -goog.net.BrowserChannel.prototype.onRequestComplete = - function(request) { - this.channelDebug_.debug('Request complete'); - var type; - if (this.backChannelRequest_ == request) { - this.clearDeadBackchannelTimer_(); - this.backChannelRequest_ = null; - type = goog.net.BrowserChannel.ChannelType_.BACK_CHANNEL; - } else if (this.forwardChannelRequest_ == request) { - this.forwardChannelRequest_ = null; - type = goog.net.BrowserChannel.ChannelType_.FORWARD_CHANNEL; - } else { - // return if it was an old request from a previous session - return; - } - - this.lastStatusCode_ = request.getLastStatusCode(); - - if (this.state_ == goog.net.BrowserChannel.State.CLOSED) { - return; - } - - if (request.getSuccess()) { - // Yay! - if (type == goog.net.BrowserChannel.ChannelType_.FORWARD_CHANNEL) { - var size = request.getPostData() ? request.getPostData().length : 0; - goog.net.BrowserChannel.notifyTimingEvent(size, - goog.now() - request.getRequestStartTime(), - this.forwardChannelRetryCount_); - this.ensureForwardChannel_(); - this.pendingMaps_.length = 0; - } else { // i.e., back-channel - this.ensureBackChannel_(); - } - return; - } - // Else unsuccessful. Fall through. - - var lastError = request.getLastError(); - if (!goog.net.BrowserChannel.isFatalError_(lastError, - this.lastStatusCode_)) { - // Maybe retry. - this.channelDebug_.debug('Maybe retrying, last error: ' + - goog.net.ChannelRequest.errorStringFromCode( - /** @type {goog.net.ChannelRequest.Error} */ (lastError), - this.lastStatusCode_)); - if (type == goog.net.BrowserChannel.ChannelType_.FORWARD_CHANNEL) { - if (this.maybeRetryForwardChannel_(request)) { - return; - } - } - if (type == goog.net.BrowserChannel.ChannelType_.BACK_CHANNEL) { - if (this.maybeRetryBackChannel_()) { - return; - } - } - // Else exceeded max retries. Fall through. - this.channelDebug_.debug('Exceeded max number of retries'); - } else { - // Else fatal error. Fall through and mark the pending maps as failed. - this.channelDebug_.debug('Not retrying due to error type'); - } - - - // Can't save this session. :( - this.channelDebug_.debug('Error: HTTP request failed'); - switch (lastError) { - case goog.net.ChannelRequest.Error.NO_DATA: - this.signalError_(goog.net.BrowserChannel.Error.NO_DATA); - break; - case goog.net.ChannelRequest.Error.BAD_DATA: - this.signalError_(goog.net.BrowserChannel.Error.BAD_DATA); - break; - case goog.net.ChannelRequest.Error.UNKNOWN_SESSION_ID: - this.signalError_(goog.net.BrowserChannel.Error.UNKNOWN_SESSION_ID); - break; - default: - this.signalError_(goog.net.BrowserChannel.Error.REQUEST_FAILED); - break; - } -}; - - -/** - * @param {number} retryCount Number of retries so far. - * @return {number} Time in ms before firing next retry request. - * @private - */ -goog.net.BrowserChannel.prototype.getRetryTime_ = function(retryCount) { - var retryTime = goog.net.BrowserChannel.RETRY_DELAY_MS + - Math.floor(Math.random() * goog.net.BrowserChannel.RETRY_DELAY_SEED); - if (!this.isActive()) { - this.channelDebug_.debug('Inactive channel'); - retryTime = - retryTime * goog.net.BrowserChannel.INACTIVE_CHANNEL_RETRY_FACTOR; - } - // Backoff for subsequent retries - retryTime = retryTime * retryCount; - return retryTime; -}; - - -/** - * Processes the data returned by the server. - * @param {Array} respArray The response array returned by the server. - * @private - */ -goog.net.BrowserChannel.prototype.onInput_ = function(respArray) { - // respArray is an array of arrays - var batch = this.handler_ && this.handler_.channelHandleMultipleArrays ? - [] : null; - for (var i = 0; i < respArray.length; i++) { - var nextArray = respArray[i]; - this.lastArrayId_ = nextArray[0]; - nextArray = nextArray[1]; - if (this.state_ == goog.net.BrowserChannel.State.OPENING) { - if (nextArray[0] == 'c') { - this.sid_ = nextArray[1]; - this.hostPrefix_ = this.correctHostPrefix(nextArray[2]); - var negotiatedVersion = nextArray[3]; - if (goog.isDefAndNotNull(negotiatedVersion)) { - this.channelVersion_ = negotiatedVersion; - } else { - // Servers prior to version 7 did not send this, so assume version 6. - this.channelVersion_ = 6; - } - this.state_ = goog.net.BrowserChannel.State.OPENED; - if (this.handler_) { - this.handler_.channelOpened(this); - } - this.backChannelUri_ = this.getBackChannelUri( - this.hostPrefix_, /** @type {string} */ (this.path_)); - // Open connection to receive data - this.ensureBackChannel_(); - } else if (nextArray[0] == 'stop') { - this.signalError_(goog.net.BrowserChannel.Error.STOP); - } - } else if (this.state_ == goog.net.BrowserChannel.State.OPENED) { - if (nextArray[0] == 'stop') { - if (batch && batch.length) { - this.handler_.channelHandleMultipleArrays(this, batch); - batch.length = 0; - } - this.signalError_(goog.net.BrowserChannel.Error.STOP); - } else if (nextArray[0] == 'noop') { - // ignore - noop to keep connection happy - } else { - if (batch) { - batch.push(nextArray); - } else if (this.handler_) { - this.handler_.channelHandleArray(this, nextArray); - } - } - // We have received useful data on the back-channel, so clear its retry - // count. We do this because back-channels by design do not complete - // quickly, so on a flaky connection we could have many fail to complete - // fully but still deliver a lot of data before they fail. We don't want - // to count such failures towards the retry limit, because we don't want - // to give up on a session if we can still receive data. - this.backChannelRetryCount_ = 0; - } - } - if (batch && batch.length) { - this.handler_.channelHandleMultipleArrays(this, batch); - } -}; - - -/** - * Helper to ensure the BrowserChannel is in the expected state. - * @param {...number} var_args The channel must be in one of the indicated - * states. - * @private - */ -goog.net.BrowserChannel.prototype.ensureInState_ = function(var_args) { - if (!goog.array.contains(arguments, this.state_)) { - throw Error('Unexpected channel state: ' + this.state_); - } -}; - - -/** - * Signals an error has occurred. - * @param {goog.net.BrowserChannel.Error} error The error code for the failure. - * @private - */ -goog.net.BrowserChannel.prototype.signalError_ = function(error) { - this.channelDebug_.info('Error code ' + error); - if (error == goog.net.BrowserChannel.Error.REQUEST_FAILED || - error == goog.net.BrowserChannel.Error.BLOCKED) { - // Ping google to check if it's a server error or user's network error. - var imageUri = null; - if (this.handler_) { - imageUri = this.handler_.getNetworkTestImageUri(this); - } - goog.net.tmpnetwork.testGoogleCom( - goog.bind(this.testGoogleComCallback_, this), imageUri); - } else { - goog.net.BrowserChannel.notifyStatEvent( - goog.net.BrowserChannel.Stat.ERROR_OTHER); - } - this.onError_(error); -}; - - -/** - * Callback for testGoogleCom during error handling. - * @param {boolean} networkUp Whether the network is up. - * @private - */ -goog.net.BrowserChannel.prototype.testGoogleComCallback_ = function(networkUp) { - if (networkUp) { - this.channelDebug_.info('Successfully pinged google.com'); - goog.net.BrowserChannel.notifyStatEvent( - goog.net.BrowserChannel.Stat.ERROR_OTHER); - } else { - this.channelDebug_.info('Failed to ping google.com'); - goog.net.BrowserChannel.notifyStatEvent( - goog.net.BrowserChannel.Stat.ERROR_NETWORK); - // We cann onError_ here instead of signalError_ because the latter just - // calls notifyStatEvent, and we don't want to have another stat event. - this.onError_(goog.net.BrowserChannel.Error.NETWORK); - } -}; - - -/** - * Called when we've determined the final error for a channel. It closes the - * notifiers the handler of the error and closes the channel. - * @param {goog.net.BrowserChannel.Error} error The error code for the failure. - * @private - */ -goog.net.BrowserChannel.prototype.onError_ = function(error) { - this.channelDebug_.debug('HttpChannel: error - ' + error); - this.state_ = goog.net.BrowserChannel.State.CLOSED; - if (this.handler_) { - this.handler_.channelError(this, error); - } - this.onClose_(); - this.cancelRequests_(); -}; - - -/** - * Called when the channel has been closed. It notifiers the handler of the - * event, and reports any pending or undelivered maps. - * @private - */ -goog.net.BrowserChannel.prototype.onClose_ = function() { - this.state_ = goog.net.BrowserChannel.State.CLOSED; - this.lastStatusCode_ = -1; - if (this.handler_) { - if (this.pendingMaps_.length == 0 && this.outgoingMaps_.length == 0) { - this.handler_.channelClosed(this); - } else { - this.channelDebug_.debug('Number of undelivered maps' + - ', pending: ' + this.pendingMaps_.length + - ', outgoing: ' + this.outgoingMaps_.length); - - var copyOfPendingMaps = goog.array.clone(this.pendingMaps_); - var copyOfUndeliveredMaps = goog.array.clone(this.outgoingMaps_); - this.pendingMaps_.length = 0; - this.outgoingMaps_.length = 0; - - this.handler_.channelClosed(this, - copyOfPendingMaps, - copyOfUndeliveredMaps); - } - } -}; - - -/** - * Gets the Uri used for the connection that sends data to the server. - * @param {string} path The path on the host. - * @return {goog.Uri} The forward channel URI. - */ -goog.net.BrowserChannel.prototype.getForwardChannelUri = - function(path) { - var uri = this.createDataUri(null, path); - this.channelDebug_.debug('GetForwardChannelUri: ' + uri); - return uri; -}; - - -/** - * Gets the Uri used for the connection that receives data from the server. - * @param {?string} hostPrefix The host prefix. - * @param {string} path The path on the host. - * @return {goog.Uri} The back channel URI. - */ -goog.net.BrowserChannel.prototype.getBackChannelUri = - function(hostPrefix, path) { - var uri = this.createDataUri(this.shouldUseSecondaryDomains() ? - hostPrefix : null, path); - this.channelDebug_.debug('GetBackChannelUri: ' + uri); - return uri; -}; - - -/** - * Creates a data Uri applying logic for secondary hostprefix, port - * overrides, and versioning. - * @param {?string} hostPrefix The host prefix. - * @param {string} path The path on the host (may be absolute or relative). - * @param {number=} opt_overridePort Optional override port. - * @return {goog.Uri} The data URI. - */ -goog.net.BrowserChannel.prototype.createDataUri = - function(hostPrefix, path, opt_overridePort) { - var uri = goog.Uri.parse(path); - var uriAbsolute = (uri.getDomain() != ''); - if (uriAbsolute) { - if (hostPrefix) { - uri.setDomain(hostPrefix + '.' + uri.getDomain()); - } - - uri.setPort(opt_overridePort || uri.getPort()); - } else { - var locationPage = window.location; - var hostName; - if (hostPrefix) { - hostName = hostPrefix + '.' + locationPage.hostname; - } else { - hostName = locationPage.hostname; - } - - var port = opt_overridePort || locationPage.port; - - uri = goog.Uri.create(locationPage.protocol, null, hostName, port, path); - } - - if (this.extraParams_) { - goog.structs.forEach(this.extraParams_, function(value, key, coll) { - uri.setParameterValue(key, value); - }); - } - - // Add the protocol version to the URI. - uri.setParameterValue('VER', this.channelVersion_); - - // Add the reconnect parameters. - this.addAdditionalParams_(uri); - - return uri; -}; - - -/** - * Called when BC needs to create an XhrIo object. Override in a subclass if - * you need to customize the behavior, for example to enable the creation of - * XHR's capable of calling a secondary domain. - * @param {?string} hostPrefix The host prefix, if we need an XhrIo object - * capable of calling a secondary domain. - * @return {!goog.net.XhrIo} A new XhrIo object. - */ -goog.net.BrowserChannel.prototype.createXhrIo = function(hostPrefix) { - if (hostPrefix) { - throw new Error('Can\'t create secondary domain capable XhrIo object.'); - } else { - return new goog.net.XhrIo(); - } -}; - - -/** - * Gets whether this channel is currently active. This is used to determine the - * length of time to wait before retrying. This call delegates to the handler. - * @return {boolean} Whether the channel is currently active. - */ -goog.net.BrowserChannel.prototype.isActive = function() { - return !!this.handler_ && this.handler_.isActive(this); -}; - - -/** - * Wrapper around SafeTimeout which calls the start and end execution hooks - * with a try...finally block. - * @param {Function} fn The callback function. - * @param {number} ms The time in MS for the timer. - * @return {number} The ID of the timer. - */ -goog.net.BrowserChannel.setTimeout = function(fn, ms) { - if (!goog.isFunction(fn)) { - throw Error('Fn must not be null and must be a function'); - } - return goog.global.setTimeout(function() { - goog.net.BrowserChannel.onStartExecution(); - try { - fn(); - } finally { - goog.net.BrowserChannel.onEndExecution(); - } - }, ms); -}; - - -/** - * Helper function to call the start hook - */ -goog.net.BrowserChannel.onStartExecution = function() { - goog.net.BrowserChannel.startExecutionHook_(); -}; - - -/** - * Helper function to call the end hook - */ -goog.net.BrowserChannel.onEndExecution = function() { - goog.net.BrowserChannel.endExecutionHook_(); -}; - - -/** - * Returns the singleton event target for stat events. - * @return {goog.events.EventTarget} The event target for stat events. - */ -goog.net.BrowserChannel.getStatEventTarget = function() { - return goog.net.BrowserChannel.statEventTarget_; -}; - - -/** - * Helper function to call the stat event callback. - * @param {goog.net.BrowserChannel.Stat} stat The stat. - */ -goog.net.BrowserChannel.notifyStatEvent = function(stat) { - var target = goog.net.BrowserChannel.statEventTarget_; - target.dispatchEvent( - new goog.net.BrowserChannel.StatEvent(target, stat)); -}; - - -/** - * Helper function to notify listeners about POST request performance. - * - * @param {number} size Number of characters in the POST data. - * @param {number} rtt The amount of time from POST start to response. - * @param {number} retries The number of times the POST had to be retried. - */ -goog.net.BrowserChannel.notifyTimingEvent = function(size, rtt, retries) { - var target = goog.net.BrowserChannel.statEventTarget_; - target.dispatchEvent( - new goog.net.BrowserChannel.TimingEvent(target, size, rtt, retries)); -}; - - -/** - * Determines whether to use a secondary domain when the server gives us - * a host prefix. This allows us to work around browser per-domain - * connection limits. - * - * Currently, we only use secondary domains when using Trident's ActiveXObject, - * because it supports cross-domain requests out of the box. Even if we wanted - * to use secondary domains on Gecko/Webkit, they wouldn't work due to - * security restrictions on cross-origin XHRs. - * - * If you need to use secondary domains on other browsers, you'll need - * to override this method in a subclass, and make sure that those browsers - * use some messaging mechanism that works cross-domain. - * - * @return {boolean} Whether to use secondary domains. - * @see http://code.google.com/p/closure-library/issues/detail?id=339 - */ -goog.net.BrowserChannel.prototype.shouldUseSecondaryDomains = function() { - return goog.userAgent.IE; -}; - - -/** - * A LogSaver that can be used to accumulate all the debug logs for - * BrowserChannels so they can be sent to the server when a problem is - * detected. - */ -goog.net.BrowserChannel.LogSaver = {}; - - -/** - * Buffer for accumulating the debug log - * @type {goog.structs.CircularBuffer} - * @private - */ -goog.net.BrowserChannel.LogSaver.buffer_ = - new goog.structs.CircularBuffer(1000); - - -/** - * Whether we're currently accumulating the debug log. - * @type {boolean} - * @private - */ -goog.net.BrowserChannel.LogSaver.enabled_ = false; - - -/** - * Formatter for saving logs. - * @type {goog.debug.Formatter} - * @private - */ -goog.net.BrowserChannel.LogSaver.formatter_ = new goog.debug.TextFormatter(); - - -/** - * Returns whether the LogSaver is enabled. - * @return {boolean} Whether saving is enabled or disabled. - */ -goog.net.BrowserChannel.LogSaver.isEnabled = function() { - return goog.net.BrowserChannel.LogSaver.enabled_; -}; - - -/** - * Enables of disables the LogSaver. - * @param {boolean} enable Whether to enable or disable saving. - */ -goog.net.BrowserChannel.LogSaver.setEnabled = function(enable) { - if (enable == goog.net.BrowserChannel.LogSaver.enabled_) { - return; - } - - var fn = goog.net.BrowserChannel.LogSaver.addLogRecord; - var logger = goog.debug.Logger.getLogger('goog.net'); - if (enable) { - logger.addHandler(fn); - } else { - logger.removeHandler(fn); - } -}; - - -/** - * Adds a log record. - * @param {goog.debug.LogRecord} logRecord the LogRecord. - */ -goog.net.BrowserChannel.LogSaver.addLogRecord = function(logRecord) { - goog.net.BrowserChannel.LogSaver.buffer_.add( - goog.net.BrowserChannel.LogSaver.formatter_.formatRecord(logRecord)); -}; - - -/** - * Returns the log as a single string. - * @return {string} The log as a single string. - */ -goog.net.BrowserChannel.LogSaver.getBuffer = function() { - return goog.net.BrowserChannel.LogSaver.buffer_.getValues().join(''); -}; - - -/** - * Clears the buffer - */ -goog.net.BrowserChannel.LogSaver.clearBuffer = function() { - goog.net.BrowserChannel.LogSaver.buffer_.clear(); -}; - - - -/** - * Interface for the browser channel handler - * @constructor - */ -goog.net.BrowserChannel.Handler = function() { -}; - - -/** - * Callback handler for when a batch of response arrays is received from the - * server. - * @type {Function} - */ -goog.net.BrowserChannel.Handler.prototype.channelHandleMultipleArrays = null; - - -/** - * Whether it's okay to make a request to the server. A handler can return - * false if the channel should fail. For example, if the user has logged out, - * the handler may want all requests to fail immediately. - * @param {goog.net.BrowserChannel} browserChannel The browser channel. - * @return {goog.net.BrowserChannel.Error} An error code. The code should - * return goog.net.BrowserChannel.Error.OK to indicate it's okay. Any other - * error code will cause a failure. - */ -goog.net.BrowserChannel.Handler.prototype.okToMakeRequest = - function(browserChannel) { - return goog.net.BrowserChannel.Error.OK; -}; - - -/** - * Indicates the BrowserChannel has successfully negotiated with the server - * and can now send and receive data. - * @param {goog.net.BrowserChannel} browserChannel The browser channel. - */ -goog.net.BrowserChannel.Handler.prototype.channelOpened = - function(browserChannel) { -}; - - -/** - * New input is available for the application to process. - * - * @param {goog.net.BrowserChannel} browserChannel The browser channel. - * @param {Array} array The data array. - */ -goog.net.BrowserChannel.Handler.prototype.channelHandleArray = - function(browserChannel, array) { -}; - - -/** - * Indicates an error occurred on the BrowserChannel. - * - * @param {goog.net.BrowserChannel} browserChannel The browser channel. - * @param {goog.net.BrowserChannel.Error} error The error code. - */ -goog.net.BrowserChannel.Handler.prototype.channelError = - function(browserChannel, error) { -}; - - -/** - * Indicates the BrowserChannel is closed. Also notifies about which maps, - * if any, that may not have been delivered to the server. - * @param {goog.net.BrowserChannel} browserChannel The browser channel. - * @param {Array.<goog.net.BrowserChannel.QueuedMap>=} opt_pendingMaps The - * array of pending maps, which may or may not have been delivered to the - * server. - * @param {Array.<goog.net.BrowserChannel.QueuedMap>=} opt_undeliveredMaps - * The array of undelivered maps, which have definitely not been delivered - * to the server. - */ -goog.net.BrowserChannel.Handler.prototype.channelClosed = - function(browserChannel, opt_pendingMaps, opt_undeliveredMaps) { -}; - - -/** - * Gets any parameters that should be added at the time another connection is - * made to the server. - * @param {goog.net.BrowserChannel} browserChannel The browser channel. - * @return {Object} Extra parameter keys and values to add to the - * requests. - */ -goog.net.BrowserChannel.Handler.prototype.getAdditionalParams = - function(browserChannel) { - return {}; -}; - - -/** - * Gets the URI of an image that can be used to test network connectivity. - * @param {goog.net.BrowserChannel} browserChannel The browser channel. - * @return {goog.Uri?} A custom URI to load for the network test. - */ -goog.net.BrowserChannel.Handler.prototype.getNetworkTestImageUri = - function(browserChannel) { - return null; -}; - - -/** - * Gets whether this channel is currently active. This is used to determine the - * length of time to wait before retrying. - * @param {goog.net.BrowserChannel} browserChannel The browser channel. - * @return {boolean} Whether the channel is currently active. - */ -goog.net.BrowserChannel.Handler.prototype.isActive = function(browserChannel) { - return true; -}; - - -/** - * Called by the channel if enumeration of the map throws an exception. - * @param {goog.net.BrowserChannel} browserChannel The browser channel. - * @param {Object} map The map that can't be enumerated. - */ -goog.net.BrowserChannel.Handler.prototype.badMapError = - function(browserChannel, map) { - return; -}; - - -/** - * Allows the handler to override a host prefix provided by the server. Will - * be called whenever the channel has received such a prefix and is considering - * its use. - * @param {?string} serverHostPrefix The host prefix provided by the server. - * @return {?string} The host prefix the client should use. - */ -goog.net.BrowserChannel.Handler.prototype.correctHostPrefix = - function(serverHostPrefix) { - return serverHostPrefix; -}; diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/browserchannel_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/browserchannel_test.html.svn-base deleted file mode 100644 index 89bce9e..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/browserchannel_test.html.svn-base +++ /dev/null @@ -1,1200 +0,0 @@ -<!DOCTYPE html> -<html> -<!-- -Copyright 2009 The Closure Library Authors. All Rights Reserved. - -Use of this source code is governed by the Apache License, Version 2.0. -See the COPYING file for details. ---> -<!-- ---> -<head> -<meta http-equiv="X-UA-Compatible" content="IE=edge"> -<title>Closure Unit Tests - goog.net.BrowserChannel</title> -<script type="text/javascript" src="../base.js"></script> -<script type="text/javascript"> - goog.require('goog.Timer'); - goog.require('goog.dom'); - goog.require('goog.functions'); - goog.require('goog.json'); - goog.require('goog.net.BrowserChannel'); - goog.require('goog.net.ChannelRequest'); - goog.require('goog.net.tmpnetwork'); - goog.require('goog.string.StringBuffer'); - goog.require('goog.structs.Map'); - goog.require('goog.testing.MockClock'); - goog.require('goog.testing.asserts'); - goog.require('goog.testing.jsunit'); -</script> -</head> -<body> - -<!-- Define unit tests. --> -<script type="text/javascript" > - -/** - * Delay between a network failure and the next network request. - */ -var RETRY_TIME = 1000; - -/** - * A really long time - used to make sure no more timeouts will fire. - */ -var ALL_DAY_MS = 1000 * 60 * 60 * 24; - -var browserChannel; -var handler; -var mockClock; -var sb; -var gotError; -var numStatEvents; -var lastStatEvent; -var numTimingEvents; -var lastPostSize; -var lastPostRtt; -var lastPostRetryCount; - -// Set to true to see the channel debug output in the browser window. -var debug = false; - -function debugToWindow(message) { - if (debug) { - sb.append(message + '<br>'); - goog.dom.getElement('debug').innerHTML = sb.toString(); - } -} - - -/** - * Mock ChannelRequest. - */ -function MockChannelRequest() {} -MockChannelRequest = function(channel, channelDebug, opt_sessionId, - opt_requestId, opt_retryId) { - this.channel_ = channel; - this.channelDebug_ = channelDebug; - this.sessionId_ = opt_sessionId; - this.requestId_ = opt_requestId; - this.successful_ = true; - this.lastError_ = null; - this.lastStatusCode_ = 200; - - // For debugging, keep track of whether this is a back or forward channel. - this.isBack = !!(opt_requestId == 'rpc'); - this.isForward = !this.isBack; -}; - -MockChannelRequest.prototype.postData_ = null; - -MockChannelRequest.prototype.requestStartTime_ = null; - -MockChannelRequest.prototype.setExtraHeaders = function(extraHeaders) {}; - -MockChannelRequest.prototype.setTimeout = function(timeout) {}; - -MockChannelRequest.prototype.xmlHttpPost = function(uri, postData, - decodeChunks) { - this.channelDebug_.debug('---> POST: ' + uri + ', ' + postData + ', ' + - decodeChunks); - this.postData_ = postData; - this.requestStartTime_ = goog.now() -}; - -MockChannelRequest.prototype.xmlHttpGet = function(uri, decodeChunks, - opt_noClose) { - this.channelDebug_.debug('<--- GET: ' + uri + ', ' + decodeChunks + ', ' + - opt_noClose); - this.requestStartTime_ = goog.now() -}; - -MockChannelRequest.prototype.tridentGet = function(uri, usingSecondaryDomain) { - this.channelDebug_.debug('<---GET (T): ' + uri); - this.requestStartTime_ = goog.now() -}; - -MockChannelRequest.prototype.sendUsingImgTag = function(uri) { - this.requestStartTime_ = goog.now() -}; - -MockChannelRequest.prototype.cancel = function() { - this.successful_ = false; -}; - -MockChannelRequest.prototype.getSuccess = function() { - return this.successful_; -}; - -MockChannelRequest.prototype.getLastError = function() { - return this.lastError_; -}; - -MockChannelRequest.prototype.getLastStatusCode = function() { - return this.lastStatusCode_; -}; - -MockChannelRequest.prototype.getSessionId = function() { - return this.sessionId_; -}; - -MockChannelRequest.prototype.getRequestId = function() { - return this.requestId_; -}; - -MockChannelRequest.prototype.getPostData = function() { - return this.postData_; -}; - -MockChannelRequest.prototype.getRequestStartTime = function() { - return this.requestStartTime_; -}; - - -function setUpPage() { - // Use our MockChannelRequests instead of the real ones. - goog.net.BrowserChannel.createChannelRequest = function( - channel, channelDebug, opt_sessionId, opt_requestId, opt_retryId) { - return new MockChannelRequest( - channel, channelDebug, opt_sessionId, opt_requestId, opt_retryId); - }; - sb = new goog.string.StringBuffer(); - - // Mock out the stat notification code. - goog.net.BrowserChannel.notifyStatEvent = function(stat) { - numStatEvents++; - lastStatEvent = stat; - }; - - goog.net.BrowserChannel.notifyTimingEvent = function(size, rtt, retries) { - numTimingEvents++; - lastPostSize = size; - lastPostRtt = rtt; - lastPostRetryCount = retries; - }; -} - - -function setUp() { - numTimingEvents = 0; - lastPostSize = null; - lastPostRtt = null; - lastPostRetryCount = null; - - mockClock = new goog.testing.MockClock(true); - browserChannel = new goog.net.BrowserChannel('1'); - gotError = false; - - handler = new goog.net.BrowserChannel.Handler(); - handler.channelOpened = function() {}; - handler.channelError = function(channel, error) { - gotError = true; - }; - handler.channelClosed = function( - channel, opt_pendingMaps, opt_undeliveredMaps) { - // Mock out the handler, and let it set a formatted user readable string - // of the undelivered maps which we can use when verifying our assertions. - if (opt_pendingMaps) { - this.pendingMapsString = formatArrayOfMaps(opt_pendingMaps); - } - if (opt_undeliveredMaps) { - this.undeliveredMapsString = formatArrayOfMaps(opt_undeliveredMaps); - } - }; - handler.channelHandleMultipleArrays = function() {}; - handler.channelHandleArray = function() {}; - - browserChannel.setHandler(handler); - - // Provide a predictable retry time for testing. - browserChannel.getRetryTime_ = function(retryCount) { - return RETRY_TIME; - }; - - var channelDebug = new goog.net.ChannelDebug(); - channelDebug.debug = function(message) { - debugToWindow(message); - }; - browserChannel.setChannelDebug(channelDebug); - - numStatEvents = 0; - lastStatEvent = null; -} - - -function tearDown() { - mockClock.dispose(); - debugToWindow('<hr>'); -} - - -/** - * Helper function to return a formatted string representing an array of maps. - */ -function formatArrayOfMaps(arrayOfMaps) { - var result = []; - for (var i = 0; i < arrayOfMaps.length; i++) { - var map = arrayOfMaps[i]; - var keys = map.map.getKeys(); - for (var j = 0; j < keys.length; j++) { - result.push(keys[j] + ':' + map.map.get(keys[j])); - } - } - return result.join(', '); -} - - -function testFormatArrayOfMaps() { - // This function is used in a non-trivial test, so let's verify that it works. - var map1 = new goog.structs.Map(); - map1.set('k1', 'v1'); - map1.set('k2', 'v2'); - var map2 = new goog.structs.Map(); - map2.set('k3', 'v3'); - var map3 = new goog.structs.Map(); - map3.set('k4', 'v4'); - map3.set('k5', 'v5'); - map3.set('k6', 'v6'); - - // One map. - var a = []; - a.push(new goog.net.BrowserChannel.QueuedMap(0, map1)); - assertEquals('k1:v1, k2:v2', - formatArrayOfMaps(a)); - - // Many maps. - var b = []; - b.push(new goog.net.BrowserChannel.QueuedMap(0, map1)); - b.push(new goog.net.BrowserChannel.QueuedMap(0, map2)); - b.push(new goog.net.BrowserChannel.QueuedMap(0, map3)); - assertEquals('k1:v1, k2:v2, k3:v3, k4:v4, k5:v5, k6:v6', - formatArrayOfMaps(b)); -} - - -function connect(opt_serverVersion, opt_hostPrefix, opt_uriPrefix) { - var uriPrefix = opt_uriPrefix || ''; - browserChannel.connect(uriPrefix + '/test', uriPrefix + '/bind', null); - mockClock.tick(0); - completeTestConnection(); - completeForwardChannel(opt_serverVersion, opt_hostPrefix); - completeBackChannel(); -} - - -function disconnect() { - browserChannel.disconnect(); - mockClock.tick(0); -} - - -function completeTestConnection() { - completeForwardTestConnection(); - completeBackTestConnection(); - assertEquals(goog.net.BrowserChannel.State.OPENING, - browserChannel.getState()); -} - - -function completeForwardTestConnection() { - browserChannel.connectionTest_.onRequestData( - browserChannel.connectionTest_, - '["b"]'); - browserChannel.connectionTest_.onRequestComplete( - browserChannel.connectionTest_); - mockClock.tick(0); -} - - -function completeBackTestConnection() { - browserChannel.connectionTest_.onRequestData( - browserChannel.connectionTest_, - '11111'); - mockClock.tick(0); -} - - -function completeForwardChannel(opt_serverVersion, opt_hostPrefix) { - var responseData = '[[0,["c","1234567890ABCDEF",' + - (opt_hostPrefix ? '"' + opt_hostPrefix + '"' : 'null') + - (opt_serverVersion ? ',' + opt_serverVersion : '') + - ']]]'; - browserChannel.onRequestData( - browserChannel.forwardChannelRequest_, - responseData); - browserChannel.onRequestComplete( - browserChannel.forwardChannelRequest_); - mockClock.tick(0); -} - - -function completeBackChannel() { - browserChannel.onRequestData( - browserChannel.backChannelRequest_, - '[[1,["foo"]]]'); - browserChannel.onRequestComplete( - browserChannel.backChannelRequest_); - mockClock.tick(0); -} - - -function responseVersion7() { - browserChannel.onRequestData( - browserChannel.forwardChannelRequest_, - goog.net.BrowserChannel.MAGIC_RESPONSE_COOKIE); - browserChannel.onRequestComplete( - browserChannel.forwardChannelRequest_); - mockClock.tick(0); -} - -function responseNoBackchannel(lastArrayIdSentFromServer, outstandingDataSize) { - responseData = goog.json.serialize( - [0, lastArrayIdSentFromServer, outstandingDataSize]); - browserChannel.onRequestData( - browserChannel.forwardChannelRequest_, - responseData); - browserChannel.onRequestComplete( - browserChannel.forwardChannelRequest_); - mockClock.tick(0); -} - -function response(lastArrayIdSentFromServer, outstandingDataSize) { - responseData = goog.json.serialize( - [1, lastArrayIdSentFromServer, outstandingDataSize]); - browserChannel.onRequestData( - browserChannel.forwardChannelRequest_, - responseData - ); - browserChannel.onRequestComplete( - browserChannel.forwardChannelRequest_); - mockClock.tick(0); -} - - -function receive(data) { - browserChannel.onRequestData( - browserChannel.backChannelRequest_, - '[[1,' + data + ']]'); - browserChannel.onRequestComplete( - browserChannel.backChannelRequest_); - mockClock.tick(0); -} - - -function responseTimeout() { - browserChannel.forwardChannelRequest_lastError_ = - goog.net.ChannelRequest.Error.TIMEOUT; - browserChannel.forwardChannelRequest_.successful_ = false; - browserChannel.onRequestComplete( - browserChannel.forwardChannelRequest_); - mockClock.tick(0); -} - - -function responseRequestFailed(opt_statusCode) { - browserChannel.forwardChannelRequest_.lastError_ = - goog.net.ChannelRequest.Error.STATUS; - browserChannel.forwardChannelRequest_.lastStatusCode_ = - opt_statusCode || 503; - browserChannel.forwardChannelRequest_.successful_ = false; - browserChannel.onRequestComplete( - browserChannel.forwardChannelRequest_); - mockClock.tick(0); -} - - -function responseUnknownSessionId() { - browserChannel.forwardChannelRequest_.lastError_ = - goog.net.ChannelRequest.Error.UNKNOWN_SESSION_ID; - browserChannel.forwardChannelRequest_.successful_ = false; - browserChannel.onRequestComplete( - browserChannel.forwardChannelRequest_); - mockClock.tick(0); -} - - -function sendMap(key, value) { - var map = new goog.structs.Map(); - map.set(key, value); - browserChannel.sendMap(map); - mockClock.tick(0); -} - - -function hasForwardChannel() { - return !!browserChannel.forwardChannelRequest_; -} - - -function hasBackChannel() { - return !!browserChannel.backChannelRequest_; -} - - -function hasDeadBackChannelTimer() { - return goog.isDefAndNotNull(browserChannel.deadBackChannelTimerId_); -}; - - -function assertHasForwardChannel() { - assertTrue('Forward channel missing.', hasForwardChannel()); -} - - -function assertHasBackChannel() { - assertTrue('Back channel missing.', hasBackChannel()); -} - - -function testConnect() { - connect(); - assertEquals(goog.net.BrowserChannel.State.OPENED, - browserChannel.getState()); - // If the server specifies no version, the client assumes 6 - assertEquals(6, browserChannel.channelVersion_); - assertFalse(browserChannel.isBuffered()); -} - -function testConnect_backChannelEstablished() { - connect(); - assertHasBackChannel(); -} - -function testConnect_withServerHostPrefix() { - connect(undefined, 'serverHostPrefix'); - assertEquals('serverHostPrefix', browserChannel.hostPrefix_); -} - -function testConnect_withClientHostPrefix() { - handler.correctHostPrefix = function(hostPrefix) { - return 'clientHostPrefix'; - } - connect(); - assertEquals('clientHostPrefix', browserChannel.hostPrefix_); -} - -function testConnect_overrideServerHostPrefix() { - handler.correctHostPrefix = function(hostPrefix) { - return 'clientHostPrefix'; - } - connect(undefined, 'serverHostPrefix'); - assertEquals('clientHostPrefix', browserChannel.hostPrefix_); -} - -function testConnect_withServerVersion() { - connect(8); - assertEquals(8, browserChannel.channelVersion_); -} - -function testConnect_notOkToMakeRequestForTest() { - handler.okToMakeRequest = - goog.functions.constant(goog.net.BrowserChannel.Error.NETWORK); - browserChannel.connect('/test', '/bind', null); - mockClock.tick(0); - assertEquals(goog.net.BrowserChannel.State.CLOSED, browserChannel.getState()); -} - -function testConnect_notOkToMakeRequestForBind() { - browserChannel.connect('/test', '/bind', null); - mockClock.tick(0); - completeTestConnection(); - handler.okToMakeRequest = - goog.functions.constant(goog.net.BrowserChannel.Error.NETWORK); - completeForwardChannel(); - assertEquals(goog.net.BrowserChannel.State.CLOSED, browserChannel.getState()); -} - - -function testSendMap() { - connect(); - assertEquals(1, numTimingEvents); - sendMap('foo', 'bar'); - responseVersion7(); - assertEquals(2, numTimingEvents); -} - - -function testSendMap_twice() { - connect(); - sendMap('foo1', 'bar1'); - responseVersion7(); - sendMap('foo2', 'bar2'); - responseVersion7(); -} - - -function testSendMap_andReceive() { - connect(); - sendMap('foo', 'bar'); - responseVersion7(); - receive('["the server reply"]'); -} - - -function testReceive() { - connect(); - receive('["message from server"]'); - assertHasBackChannel(); -} - - -function testReceive_twice() { - connect(); - receive('["message one from server"]'); - receive('["message two from server"]'); - assertHasBackChannel(); -} - - -function testReceive_andSendMap() { - connect(); - receive('["the server reply"]'); - sendMap('foo', 'bar'); - responseVersion7(); - assertHasBackChannel(); -} - - -function testBackChannelRemainsEstablished_afterSingleSendMap() { - connect(); - - sendMap('foo', 'bar'); - responseVersion7(); - receive('["ack"]'); - - assertHasBackChannel(); -} - - -function testBackChannelRemainsEstablished_afterDoubleSendMap() { - connect(); - - sendMap('foo1', 'bar1'); - sendMap('foo2', 'bar2'); - responseVersion7(); - receive('["ack"]'); - - // This assertion would fail prior to CL 13302660. - assertHasBackChannel(); -} - - -function testTimingEvent(){ - connect(); - assertEquals(1, numTimingEvents); - sendMap('', ''); - assertEquals(1, numTimingEvents); - mockClock.tick(20); - var expSize = browserChannel.forwardChannelRequest_.getPostData().length; - responseVersion7(); - - assertEquals(2, numTimingEvents); - assertEquals(expSize, lastPostSize); - assertEquals(20, lastPostRtt); - assertEquals(0, lastPostRetryCount); - - sendMap('abcdefg', '123456'); - expSize = browserChannel.forwardChannelRequest_.getPostData().length; - responseTimeout(); - assertEquals(2, numTimingEvents); - mockClock.tick(RETRY_TIME + 1); - responseVersion7(); - assertEquals(3, numTimingEvents); - assertEquals(expSize, lastPostSize); - assertEquals(1, lastPostRetryCount); - assertEquals(1, lastPostRtt); - -} - - -/** - * Make sure that dropping the forward channel retry limit below the retry count - * reports an error, and prevents another request from firing. - */ -function testSetFailFastWhileWaitingForRetry() { - connect(); - assertEquals(1, numTimingEvents); - - sendMap('foo', 'bar'); - assertNull(browserChannel.forwardChannelTimerId_); - assertNotNull(browserChannel.forwardChannelRequest_); - assertEquals(0, browserChannel.forwardChannelRetryCount_); - - // Watchdog timeout. - responseTimeout(); - assertNotNull(browserChannel.forwardChannelTimerId_); - assertNull(browserChannel.forwardChannelRequest_); - assertEquals(1, browserChannel.forwardChannelRetryCount_); - - // Almost finish the between-retry timeout. - mockClock.tick(RETRY_TIME - 1); - assertNotNull(browserChannel.forwardChannelTimerId_); - assertNull(browserChannel.forwardChannelRequest_); - assertEquals(1, browserChannel.forwardChannelRetryCount_); - - // Setting max retries to 0 should cancel the timer and raise an error. - browserChannel.setFailFast(true); - assertNull(browserChannel.forwardChannelTimerId_); - assertNull(browserChannel.forwardChannelRequest_); - assertEquals(1, browserChannel.forwardChannelRetryCount_); - - assertTrue(gotError); - // We get the error immediately before starting to ping google.com. - // Simulate that timing out. We should get a network error in addition to the - // initial failure. - gotError = false; - mockClock.tick(goog.net.tmpnetwork.GOOGLECOM_TIMEOUT); - assertTrue(gotError); - - // Make sure no more retry timers are firing. - mockClock.tick(ALL_DAY_MS); - assertNull(browserChannel.forwardChannelTimerId_); - assertNull(browserChannel.forwardChannelRequest_); - assertEquals(1, browserChannel.forwardChannelRetryCount_); - assertEquals(1, numTimingEvents); -} - - -/** - * Make sure that dropping the forward channel retry limit below the retry count - * reports an error, and prevents another request from firing. - */ -function testSetFailFastWhileRetryXhrIsInFlight() { - connect(); - assertEquals(1, numTimingEvents); - - sendMap('foo', 'bar'); - assertNull(browserChannel.forwardChannelTimerId_); - assertNotNull(browserChannel.forwardChannelRequest_); - assertEquals(0, browserChannel.forwardChannelRetryCount_); - - // Watchdog timeout. - responseTimeout(); - assertNotNull(browserChannel.forwardChannelTimerId_); - assertNull(browserChannel.forwardChannelRequest_); - assertEquals(1, browserChannel.forwardChannelRetryCount_); - - // Wait for the between-retry timeout. - mockClock.tick(RETRY_TIME); - assertNull(browserChannel.forwardChannelTimerId_); - assertNotNull(browserChannel.forwardChannelRequest_); - assertEquals(1, browserChannel.forwardChannelRetryCount_); - - // Simulate a second watchdog timeout. - responseTimeout(); - assertNotNull(browserChannel.forwardChannelTimerId_); - assertNull(browserChannel.forwardChannelRequest_); - assertEquals(2, browserChannel.forwardChannelRetryCount_); - - // Wait for another between-retry timeout. - mockClock.tick(RETRY_TIME); - // Now the third req is in flight. - assertNull(browserChannel.forwardChannelTimerId_); - assertNotNull(browserChannel.forwardChannelRequest_); - assertEquals(2, browserChannel.forwardChannelRetryCount_); - - // Set fail fast, killing the request - browserChannel.setFailFast(true); - assertNull(browserChannel.forwardChannelTimerId_); - assertNull(browserChannel.forwardChannelRequest_); - assertEquals(2, browserChannel.forwardChannelRetryCount_); - - assertTrue(gotError); - // We get the error immediately before starting to ping google.com. - // Simulate that timing out. We should get a network error in addition to the - gotError = false; - mockClock.tick(goog.net.tmpnetwork.GOOGLECOM_TIMEOUT); - assertTrue(gotError); - - // Make sure no more retry timers are firing. - mockClock.tick(ALL_DAY_MS); - assertNull(browserChannel.forwardChannelTimerId_); - assertNull(browserChannel.forwardChannelRequest_); - assertEquals(2, browserChannel.forwardChannelRetryCount_); - assertEquals(1, numTimingEvents); -} - - -/** - * Makes sure that setting fail fast while not retrying doesn't cause a failure. - */ -function testSetFailFastAtRetryCount() { - connect(); - assertEquals(1, numTimingEvents); - - sendMap('foo', 'bar'); - assertNull(browserChannel.forwardChannelTimerId_); - assertNotNull(browserChannel.forwardChannelRequest_); - assertEquals(0, browserChannel.forwardChannelRetryCount_); - - // Set fail fast. - browserChannel.setFailFast(true); - // Request should still be alive. - assertNull(browserChannel.forwardChannelTimerId_); - assertNotNull(browserChannel.forwardChannelRequest_); - assertEquals(0, browserChannel.forwardChannelRetryCount_); - - // Watchdog timeout. Now we should get an error. - responseTimeout(); - assertNull(browserChannel.forwardChannelTimerId_); - assertNull(browserChannel.forwardChannelRequest_); - assertEquals(0, browserChannel.forwardChannelRetryCount_); - - assertTrue(gotError); - // We get the error immediately before starting to ping google.com. - // Simulate that timing out. We should get a network error in addition to the - // initial failure. - gotError = false; - mockClock.tick(goog.net.tmpnetwork.GOOGLECOM_TIMEOUT); - assertTrue(gotError); - - // Make sure no more retry timers are firing. - mockClock.tick(ALL_DAY_MS); - assertNull(browserChannel.forwardChannelTimerId_); - assertNull(browserChannel.forwardChannelRequest_); - assertEquals(0, browserChannel.forwardChannelRetryCount_); - assertEquals(1, numTimingEvents); -} - - -function testRequestFailedClosesChannel() { - connect(); - assertEquals(1, numTimingEvents); - - sendMap('foo', 'bar'); - responseRequestFailed(); - - assertEquals('Should be closed immediately after request failed.', - goog.net.BrowserChannel.State.CLOSED, browserChannel.getState()); - - mockClock.tick(goog.net.tmpnetwork.GOOGLECOM_TIMEOUT); - - assertEquals('Should remain closed after the ping timeout.', - goog.net.BrowserChannel.State.CLOSED, browserChannel.getState()); - assertEquals(1, numTimingEvents); -} - - -function testStatEventReportedOnlyOnce() { - connect(); - sendMap('foo', 'bar'); - numStatEvents = 0; - lastStatEvent = null; - responseUnknownSessionId(); - - assertEquals(1, numStatEvents); - assertEquals(goog.net.BrowserChannel.Stat.ERROR_OTHER, lastStatEvent); - - numStatEvents = 0; - mockClock.tick(goog.net.tmpnetwork.GOOGLECOM_TIMEOUT); - assertEquals('No new stat events should be reported.', 0, numStatEvents); -} - - -function testStatEventReportedOnlyOnce_onNetworkUp() { - connect(); - sendMap('foo', 'bar'); - numStatEvents = 0; - lastStatEvent = null; - responseRequestFailed(); - - assertEquals('No stat event should be reported before we know the reason.', - 0, numStatEvents); - - // Let the ping time out. - mockClock.tick(goog.net.tmpnetwork.GOOGLECOM_TIMEOUT); - - // Assert we report the correct stat event. - assertEquals(1, numStatEvents); - assertEquals(goog.net.BrowserChannel.Stat.ERROR_NETWORK, lastStatEvent); -} - - -function testStatEventReportedOnlyOnce_onNetworkDown() { - connect(); - sendMap('foo', 'bar'); - numStatEvents = 0; - lastStatEvent = null; - responseRequestFailed(); - - assertEquals('No stat event should be reported before we know the reason.', - 0, numStatEvents); - - // Wait half the ping timeout period, and then fake the network being up. - mockClock.tick(goog.net.tmpnetwork.GOOGLECOM_TIMEOUT / 2); - browserChannel.testGoogleComCallback_(true); - - // Assert we report the correct stat event. - assertEquals(1, numStatEvents); - assertEquals(goog.net.BrowserChannel.Stat.ERROR_OTHER, lastStatEvent); -} - - -function testOutgoingMapsAwaitsResponse() { - connect(); - assertEquals(0, browserChannel.outgoingMaps_.length); - - sendMap('foo1', 'bar'); - assertEquals(0, browserChannel.outgoingMaps_.length); - sendMap('foo2', 'bar'); - assertEquals(1, browserChannel.outgoingMaps_.length); - sendMap('foo3', 'bar'); - assertEquals(2, browserChannel.outgoingMaps_.length); - sendMap('foo4', 'bar'); - assertEquals(3, browserChannel.outgoingMaps_.length); - - responseVersion7(); - // Now the forward channel request is completed and a new started, so all maps - // are dequeued from the array of outgoing maps into this new forward request. - assertEquals(0, browserChannel.outgoingMaps_.length); -} - - -function testUndeliveredMaps_doesNotNotifyWhenSuccessful() { - handler.channelClosed = function( - channel, opt_pendingMaps, opt_undeliveredMaps) { - if (opt_pendingMaps || opt_undeliveredMaps) { - fail('No pending or undelivered maps should be reported.'); - } - }; - - connect(); - sendMap('foo1', 'bar1'); - responseVersion7(); - sendMap('foo2', 'bar2'); - responseVersion7(); - disconnect(); -} - - -function testUndeliveredMaps_doesNotNotifyIfNothingWasSent() { - handler.channelClosed = function( - channel, opt_pendingMaps, opt_undeliveredMaps) { - if (opt_pendingMaps || opt_undeliveredMaps) { - fail('No pending or undelivered maps should be reported.'); - } - }; - - connect(); - mockClock.tick(ALL_DAY_MS); - disconnect(); -} - - -function testUndeliveredMaps_clearsPendingMapsAfterNotifying() { - connect(); - sendMap('foo1', 'bar1'); - sendMap('foo2', 'bar2'); - sendMap('foo3', 'bar3'); - - assertEquals(1, browserChannel.pendingMaps_.length); - assertEquals(2, browserChannel.outgoingMaps_.length); - - disconnect(); - - assertEquals(0, browserChannel.pendingMaps_.length); - assertEquals(0, browserChannel.outgoingMaps_.length); -} - - -function testUndeliveredMaps_notifiesWhenNoResponseReceived() { - connect(); - - // First send two messages that succeed. - sendMap('foo1', 'bar1'); - responseVersion7(); - sendMap('foo2', 'bar2'); - responseVersion7(); - - // Pretend the server hangs and no longer responds. - sendMap('foo3', 'bar3'); - sendMap('foo4', 'bar4'); - sendMap('foo5', 'bar5'); - - // Give up. - disconnect(); - - // Assert that we are informed of any undelivered messages; both about - // #3 that was sent but which we don't know if the server received, and - // #4 and #5 which remain in the outgoing maps and have not yet been sent. - assertEquals('foo3:bar3', handler.pendingMapsString); - assertEquals('foo4:bar4, foo5:bar5', handler.undeliveredMapsString); -} - - -function testUndeliveredMaps_serviceUnavailable() { - // Send a few maps, and let one fail. - connect(); - sendMap('foo1', 'bar1'); - responseVersion7(); - sendMap('foo2', 'bar2'); - responseRequestFailed(); - - // After a failure, the channel should be closed. - disconnect(); - - assertEquals('foo2:bar2', handler.pendingMapsString); - assertEquals('', handler.undeliveredMapsString); -} - - -function testUndeliveredMaps_onPingTimeout() { - connect(); - - // Send a message. - sendMap('foo1', 'bar1'); - - // Fake REQUEST_FAILED, triggering a ping to check the network. - responseRequestFailed(); - - // Let the ping time out, unsuccessfully. - mockClock.tick(goog.net.tmpnetwork.GOOGLECOM_TIMEOUT); - - // Assert channel is closed. - assertEquals(goog.net.BrowserChannel.State.CLOSED, - browserChannel.getState()); - - // Assert that the handler is notified about the undelivered messages. - assertEquals('foo1:bar1', handler.pendingMapsString); - assertEquals('', handler.undeliveredMapsString); -} - - -function testResponseNoBackchannelPostNotBeforeBackchannel() { - connect(8); - sendMap('foo1', 'bar1'); - - mockClock.tick(10); - assertFalse(browserChannel.backChannelRequest_.getRequestStartTime() < - browserChannel.forwardChannelRequest_.getRequestStartTime()); - responseNoBackchannel(); - assertNotEquals(goog.net.BrowserChannel.Stat.BACKCHANNEL_MISSING, - lastStatEvent); -} - - -function testResponseNoBackchannel() { - connect(8); - sendMap('foo1', 'bar1'); - response(-1, 0); - mockClock.tick(goog.net.BrowserChannel.RTT_ESTIMATE + 1); - sendMap('foo2', 'bar2'); - assertTrue(browserChannel.backChannelRequest_.getRequestStartTime() + - goog.net.BrowserChannel.RTT_ESTIMATE < - browserChannel.forwardChannelRequest_.getRequestStartTime()); - responseNoBackchannel(); - assertEquals(goog.net.BrowserChannel.Stat.BACKCHANNEL_MISSING, lastStatEvent); -} - - -function testResponseNoBackchannelWithNoBackchannel() { - connect(8); - sendMap('foo1', 'bar1'); - assertNull(browserChannel.backChannelTimerId_); - browserChannel.backChannelRequest_.cancel(); - browserChannel.backChannelRequest_ = null; - responseNoBackchannel(); - assertEquals(goog.net.BrowserChannel.Stat.BACKCHANNEL_MISSING, lastStatEvent); -} - - -function testResponseNoBackchannelWithStartTimer() { - connect(8); - sendMap('foo1', 'bar1'); - - browserChannel.backChannelRequest_.cancel(); - browserChannel.backChannelRequest_ = null; - browserChannel.backChannelTimerId_ = 123; - responseNoBackchannel(); - assertNotEquals(goog.net.BrowserChannel.Stat.BACKCHANNEL_MISSING, - lastStatEvent); -} - - -function testResponseWithNoArraySent() { - connect(8); - sendMap('foo1', 'bar1'); - - // Send a response as if the server hasn't sent down an array. - response(-1, 0); - - // POST response with an array ID lower than our last received is OK. - assertEquals(1, browserChannel.lastArrayId_); - assertEquals(-1, browserChannel.lastPostResponseArrayId_); -} - - -function testResponseWithArraysMissing() { - connect(8); - sendMap('foo1', 'bar1'); - assertEquals(-1, browserChannel.lastPostResponseArrayId_); - - // Send a response as if the server has sent down seven arrays. - response(7, 111); - - assertEquals(1, browserChannel.lastArrayId_); - assertEquals(7, browserChannel.lastPostResponseArrayId_); - mockClock.tick(goog.net.BrowserChannel.RTT_ESTIMATE * 2); - assertEquals(goog.net.BrowserChannel.Stat.BACKCHANNEL_DEAD, lastStatEvent); -} - - -function testMultipleResponsesWithArraysMissing() { - connect(8); - sendMap('foo1', 'bar1'); - assertEquals(-1, browserChannel.lastPostResponseArrayId_); - - // Send a response as if the server has sent down seven arrays. - response(7, 111); - - assertEquals(1, browserChannel.lastArrayId_); - assertEquals(7, browserChannel.lastPostResponseArrayId_); - sendMap('foo2', 'bar2'); - mockClock.tick(goog.net.BrowserChannel.RTT_ESTIMATE); - response(8, 119); - mockClock.tick(goog.net.BrowserChannel.RTT_ESTIMATE); - // The original timer should still fire. - assertEquals(goog.net.BrowserChannel.Stat.BACKCHANNEL_DEAD, lastStatEvent); -} - - -function testOnlyRetryOnceBasedOnResponse() { - connect(8); - sendMap('foo1', 'bar1'); - assertEquals(-1, browserChannel.lastPostResponseArrayId_); - - // Send a response as if the server has sent down seven arrays. - response(7, 111); - - assertEquals(1, browserChannel.lastArrayId_); - assertEquals(7, browserChannel.lastPostResponseArrayId_); - assertTrue(hasDeadBackChannelTimer()); - mockClock.tick(goog.net.BrowserChannel.RTT_ESTIMATE * 2); - assertEquals(goog.net.BrowserChannel.Stat.BACKCHANNEL_DEAD, lastStatEvent); - assertEquals(1, browserChannel.backChannelRetryCount_); - mockClock.tick(goog.net.BrowserChannel.RTT_ESTIMATE); - sendMap('foo2', 'bar2'); - assertFalse(hasDeadBackChannelTimer()); - response(8, 119); - assertFalse(hasDeadBackChannelTimer()); -} - - -function testResponseWithArraysMissingAndLiveChannel() { - connect(8); - sendMap('foo1', 'bar1'); - assertEquals(-1, browserChannel.lastPostResponseArrayId_); - - // Send a response as if the server has sent down seven arrays. - response(7, 111); - - assertEquals(1, browserChannel.lastArrayId_); - assertEquals(7, browserChannel.lastPostResponseArrayId_); - mockClock.tick(goog.net.BrowserChannel.RTT_ESTIMATE); - assertTrue(hasDeadBackChannelTimer()); - receive('["ack"]'); - assertFalse(hasDeadBackChannelTimer()); - mockClock.tick(goog.net.BrowserChannel.RTT_ESTIMATE); - assertNotEquals(goog.net.BrowserChannel.Stat.BACKCHANNEL_DEAD, lastStatEvent); -} - - -function testResponseWithBigOutstandingData() { - connect(8); - sendMap('foo1', 'bar1'); - assertEquals(-1, browserChannel.lastPostResponseArrayId_); - - // Send a response as if the server has sent down seven arrays and 50kbytes. - response(7, 50000); - - assertEquals(1, browserChannel.lastArrayId_); - assertEquals(7, browserChannel.lastPostResponseArrayId_); - assertFalse(hasDeadBackChannelTimer()); - mockClock.tick(goog.net.BrowserChannel.RTT_ESTIMATE * 2); - assertNotEquals(goog.net.BrowserChannel.Stat.BACKCHANNEL_DEAD, - lastStatEvent); -} - - -function testResponseInBufferedMode() { - connect(8); - browserChannel.useChunked_ = false; - sendMap('foo1', 'bar1'); - assertEquals(-1, browserChannel.lastPostResponseArrayId_); - response(7, 111); - - assertEquals(1, browserChannel.lastArrayId_); - assertEquals(7, browserChannel.lastPostResponseArrayId_); - assertFalse(hasDeadBackChannelTimer()); - mockClock.tick(goog.net.BrowserChannel.RTT_ESTIMATE * 2); - assertNotEquals(goog.net.BrowserChannel.Stat.BACKCHANNEL_DEAD, - lastStatEvent); -} - - -function testResponseWithGarbage() { - connect(8); - sendMap('foo1', 'bar1'); - browserChannel.onRequestData( - browserChannel.forwardChannelRequest_, - 'garbage' - ); - assertEquals(goog.net.BrowserChannel.State.CLOSED, - browserChannel.getState()); -} - - -function testResponseWithGarbageInArray() { - connect(8); - sendMap('foo1', 'bar1'); - browserChannel.onRequestData( - browserChannel.forwardChannelRequest_, - '["garbage"]' - ); - assertEquals(goog.net.BrowserChannel.State.CLOSED, - browserChannel.getState()); -} - - -function testResponseWithEvilData() { - connect(8); - sendMap('foo1', 'bar1'); - browserChannel.onRequestData( - browserChannel.forwardChannelRequest_, - goog.net.BrowserChannel.LAST_ARRAY_ID_RESPONSE_PREFIX + - '=<script>evil()\<\/script>&' + - goog.net.BrowserChannel.OUTSTANDING_DATA_RESPONSE_PREFIX + - '=<script>moreEvil()\<\/script>'); - assertEquals(goog.net.BrowserChannel.State.CLOSED, - browserChannel.getState()); -} - - -function testPathAbsolute() { - connect(8, undefined, '/talkgadget'); - assertEquals(browserChannel.backChannelUri_.getDomain(), - window.location.hostname); - assertEquals(browserChannel.forwardChannelUri_.getDomain(), - window.location.hostname); -} - - -function testPathRelative() { - connect(8, undefined, 'talkgadget'); - assertEquals(browserChannel.backChannelUri_.getDomain(), - window.location.hostname); - assertEquals(browserChannel.forwardChannelUri_.getDomain(), - window.location.hostname); -} - - -function testPathWithHost() { - connect(8, undefined, 'https://example.com'); - assertEquals(browserChannel.backChannelUri_.getScheme(), 'https'); - assertEquals(browserChannel.backChannelUri_.getDomain(), 'example.com'); - assertEquals(browserChannel.forwardChannelUri_.getScheme(), 'https'); - assertEquals(browserChannel.forwardChannelUri_.getDomain(), 'example.com'); -} - -</script> -<div id="debug" style="font-size: small"></div> -</body> -</html> diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/browsertestchannel.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/browsertestchannel.js.svn-base deleted file mode 100644 index 6a66de7..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/browsertestchannel.js.svn-base +++ /dev/null @@ -1,541 +0,0 @@ -// Copyright 2006 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Definition of the BrowserTestChannel class. A - * BrowserTestChannel is used during the first part of channel negotiation - * with the server to create the channel. It helps us determine whether we're - * behind a buffering proxy. It also runs the logic to see if the channel - * has been blocked by a network administrator. This class is part of the - * BrowserChannel implementation and is not for use by normal application code. - * - */ - - -goog.provide('goog.net.BrowserTestChannel'); - -goog.require('goog.json'); -goog.require('goog.net.ChannelRequest'); -goog.require('goog.net.ChannelRequest.Error'); -goog.require('goog.net.tmpnetwork'); -goog.require('goog.userAgent'); - - - -/** - * Encapsulates the logic for a single BrowserTestChannel. - * - * @constructor - * @param {goog.net.BrowserChannel} channel The BrowserChannel that owns this - * test channel. - * @param {goog.net.ChannelDebug} channelDebug A ChannelDebug to use for - * logging. - */ -goog.net.BrowserTestChannel = function(channel, channelDebug) { - /** - * The BrowserChannel that owns this test channel - * @type {goog.net.BrowserChannel} - * @private - */ - this.channel_ = channel; - - /** - * The channel debug to use for logging - * @type {goog.net.ChannelDebug} - * @private - */ - this.channelDebug_ = channelDebug; -}; - - -/** - * Extra HTTP headers to add to all the requests sent to the server. - * @type {Object} - * @private - */ -goog.net.BrowserTestChannel.prototype.extraHeaders_ = null; - - -/** - * The test request. - * @type {goog.net.ChannelRequest} - * @private - */ -goog.net.BrowserTestChannel.prototype.request_ = null; - - -/** - * Whether we have received the first result as an intermediate result. This - * helps us determine whether we're behind a buffering proxy. - * @type {boolean} - * @private - */ -goog.net.BrowserTestChannel.prototype.receivedIntermediateResult_ = false; - - -/** - * The time when the test request was started. We use timing in IE as - * a heuristic for whether we're behind a buffering proxy. - * @type {?number} - * @private - */ -goog.net.BrowserTestChannel.prototype.startTime_ = null; - - -/** - * The time for of the first result part. We use timing in IE as a - * heuristic for whether we're behind a buffering proxy. - * @type {?number} - * @private - */ -goog.net.BrowserTestChannel.prototype.firstTime_ = null; - - -/** - * The time for of the last result part. We use timing in IE as a - * heuristic for whether we're behind a buffering proxy. - * @type {?number} - * @private - */ -goog.net.BrowserTestChannel.prototype.lastTime_ = null; - - -/** - * The relative path for test requests. - * @type {?string} - * @private - */ -goog.net.BrowserTestChannel.prototype.path_ = null; - - -/** - * The state of the state machine for this object. - * - * @type {?number} - * @private - */ -goog.net.BrowserTestChannel.prototype.state_ = null; - - -/** - * The last status code received. - * @type {number} - * @private - */ -goog.net.BrowserTestChannel.prototype.lastStatusCode_ = -1; - - -/** - * A subdomain prefix for using a subdomain in IE for the backchannel - * requests. - * @type {?string} - * @private - */ -goog.net.BrowserTestChannel.prototype.hostPrefix_ = null; - - -/** - * A subdomain prefix for testing whether the channel was disabled by - * a network administrator; - * @type {?string} - * @private - */ -goog.net.BrowserTestChannel.prototype.blockedPrefix_ = null; - - -/** - * Enum type for the browser test channel state machine - * @enum {number} - * @private - */ -goog.net.BrowserTestChannel.State_ = { - /** - * The state for the BrowserTestChannel state machine where we making the - * initial call to get the server configured parameters. - */ - INIT: 0, - - /** - * The state for the BrowserTestChannel state machine where we're checking to - * see if the channel has been blocked. - */ - CHECKING_BLOCKED: 1, - - /** - * The state for the BrowserTestChannel state machine where we're checking to - * se if we're behind a buffering proxy. - */ - CONNECTION_TESTING: 2 -}; - - -/** - * Time in MS for waiting for the request to see if the channel is blocked. - * If the response takes longer than this many ms, we assume the request has - * failed. - * @type {number} - * @private - */ -goog.net.BrowserTestChannel.BLOCKED_TIMEOUT_ = 5000; - - -/** - * Number of attempts to try to see if the check to see if we're blocked - * succeeds. Sometimes the request can fail because of flaky network conditions - * and checking multiple times reduces false positives. - * @type {number} - * @private - */ -goog.net.BrowserTestChannel.BLOCKED_RETRIES_ = 3; - - -/** - * Time in ms between retries of the blocked request - * @type {number} - * @private - */ -goog.net.BrowserTestChannel.BLOCKED_PAUSE_BETWEEN_RETRIES_ = 2000; - - -/** - * Time between chunks in the test connection that indicates that we - * are not behind a buffering proxy. This value should be less than or - * equals to the time between chunks sent from the server. - * @type {number} - * @private - */ -goog.net.BrowserTestChannel.MIN_TIME_EXPECTED_BETWEEN_DATA_ = 500; - - -/** - * Sets extra HTTP headers to add to all the requests sent to the server. - * - * @param {Object} extraHeaders The HTTP headers. - */ -goog.net.BrowserTestChannel.prototype.setExtraHeaders = function(extraHeaders) { - this.extraHeaders_ = extraHeaders; -}; - - -/** - * Starts the test channel. This initiates connections to the server. - * - * @param {string} path The relative uri for the test connection. - */ -goog.net.BrowserTestChannel.prototype.connect = function(path) { - this.path_ = path; - var sendDataUri = this.channel_.getForwardChannelUri(this.path_); - - goog.net.BrowserChannel.notifyStatEvent( - goog.net.BrowserChannel.Stat.TEST_STAGE_ONE_START); - - // the first request returns server specific parameters - sendDataUri.setParameterValues('MODE', 'init'); - this.request_ = goog.net.BrowserChannel.createChannelRequest( - this, this.channelDebug_); - this.request_.setExtraHeaders(this.extraHeaders_); - this.request_.xmlHttpGet(sendDataUri, false /* decodeChunks */, - null /* hostPrefix */, true /* opt_noClose */); - this.state_ = goog.net.BrowserTestChannel.State_.INIT; - this.startTime_ = goog.now(); -}; - - -/** - * Checks to see whether the channel is blocked. This is for implementing the - * feature that allows network administrators to block Gmail Chat. The - * strategy to determine if we're blocked is to try to load an image off a - * special subdomain that network administrators will block access to if they - * are trying to block chat. For Gmail Chat, the subdomain is - * chatenabled.mail.google.com. - * @private - */ -goog.net.BrowserTestChannel.prototype.checkBlocked_ = function() { - var uri = this.channel_.createDataUri(this.blockedPrefix_, - '/mail/images/cleardot.gif'); - uri.makeUnique(); - goog.net.tmpnetwork.testLoadImageWithRetries(uri.toString(), - goog.net.BrowserTestChannel.BLOCKED_TIMEOUT_, - goog.bind(this.checkBlockedCallback_, this), - goog.net.BrowserTestChannel.BLOCKED_RETRIES_, - goog.net.BrowserTestChannel.BLOCKED_PAUSE_BETWEEN_RETRIES_); -}; - - -/** - * Callback for testLoadImageWithRetries to check if browser channel is - * blocked. - * @param {boolean} succeeded Whether the request succeeded. - * @private - */ -goog.net.BrowserTestChannel.prototype.checkBlockedCallback_ = function( - succeeded) { - if (succeeded) { - this.state_ = goog.net.BrowserTestChannel.State_.CONNECTION_TESTING; - this.connectStage2_(); - } else { - goog.net.BrowserChannel.notifyStatEvent( - goog.net.BrowserChannel.Stat.CHANNEL_BLOCKED); - this.channel_.testConnectionBlocked(this); - } -}; - - -/** - * Begins the second stage of the test channel where we test to see if we're - * behind a buffering proxy. The server sends back a multi-chunked response - * with the first chunk containing the content '1' and then two seconds later - * sending the second chunk containing the content '2'. Depending on how we - * receive the content, we can tell if we're behind a buffering proxy. - * @private - */ -goog.net.BrowserTestChannel.prototype.connectStage2_ = function() { - this.channelDebug_.debug('TestConnection: starting stage 2'); - this.request_ = goog.net.BrowserChannel.createChannelRequest( - this, this.channelDebug_); - this.request_.setExtraHeaders(this.extraHeaders_); - var recvDataUri = this.channel_.getBackChannelUri(this.hostPrefix_, - /** @type {string} */ (this.path_)); - - goog.net.BrowserChannel.notifyStatEvent( - goog.net.BrowserChannel.Stat.TEST_STAGE_TWO_START); - if (!goog.net.ChannelRequest.supportsXhrStreaming()) { - recvDataUri.setParameterValues('TYPE', 'html'); - this.request_.tridentGet(recvDataUri, Boolean(this.hostPrefix_)); - } else { - recvDataUri.setParameterValues('TYPE', 'xmlhttp'); - this.request_.xmlHttpGet(recvDataUri, false /** decodeChunks */, - this.hostPrefix_, false /** opt_noClose */); - } -}; - - -/** - * Factory method for XhrIo objects. - * @param {?string} hostPrefix The host prefix, if we need an XhrIo object - * capable of calling a secondary domain. - * @return {!goog.net.XhrIo} New XhrIo object. - */ -goog.net.BrowserTestChannel.prototype.createXhrIo = function(hostPrefix) { - return this.channel_.createXhrIo(hostPrefix); -}; - - -/** - * Aborts the test channel. - */ -goog.net.BrowserTestChannel.prototype.abort = function() { - if (this.request_) { - this.request_.cancel(); - this.request_ = null; - } - this.lastStatusCode_ = -1; -}; - - -/** - * Returns whether the test channel is closed. The ChannelRequest object expects - * this method to be implemented on its handler. - * - * @return {boolean} Whether the channel is closed. - */ -goog.net.BrowserTestChannel.prototype.isClosed = function() { - return false; -}; - - -/** - * Callback from ChannelRequest for when new data is received - * - * @param {goog.net.ChannelRequest} req The request object. - * @param {string} responseText The text of the response. - */ -goog.net.BrowserTestChannel.prototype.onRequestData = - function(req, responseText) { - this.lastStatusCode_ = req.getLastStatusCode(); - if (this.state_ == goog.net.BrowserTestChannel.State_.INIT) { - this.channelDebug_.debug('TestConnection: Got data for stage 1'); - if (!responseText) { - this.channelDebug_.debug('TestConnection: Null responseText'); - // The server should always send text; something is wrong here - this.channel_.testConnectionFailure(this, - goog.net.ChannelRequest.Error.BAD_DATA); - return; - } - /** @preserveTry */ - try { - var respArray = goog.json.unsafeParse(responseText); - } catch (e) { - this.channelDebug_.dumpException(e); - this.channel_.testConnectionFailure(this, - goog.net.ChannelRequest.Error.BAD_DATA); - return; - } - this.hostPrefix_ = this.channel_.correctHostPrefix(respArray[0]); - this.blockedPrefix_ = respArray[1]; - } else if (this.state_ == - goog.net.BrowserTestChannel.State_.CONNECTION_TESTING) { - if (this.receivedIntermediateResult_) { - goog.net.BrowserChannel.notifyStatEvent( - goog.net.BrowserChannel.Stat.TEST_STAGE_TWO_DATA_TWO); - this.lastTime_ = goog.now(); - } else { - // '11111' is used instead of '1' to prevent a small amount of buffering - // by Safari. - if (responseText == '11111') { - goog.net.BrowserChannel.notifyStatEvent( - goog.net.BrowserChannel.Stat.TEST_STAGE_TWO_DATA_ONE); - this.receivedIntermediateResult_ = true; - this.firstTime_ = goog.now(); - if (this.checkForEarlyNonBuffered_()) { - // If early chunk detection is on, and we passed the tests, - // assume HTTP_OK, cancel the test and turn on noproxy mode. - this.lastStatusCode_ = 200; - this.request_.cancel(); - this.channelDebug_.debug( - 'Test connection succeeded; using streaming connection'); - goog.net.BrowserChannel.notifyStatEvent( - goog.net.BrowserChannel.Stat.NOPROXY); - this.channel_.testConnectionFinished(this, true); - } - } else { - goog.net.BrowserChannel.notifyStatEvent( - goog.net.BrowserChannel.Stat.TEST_STAGE_TWO_DATA_BOTH); - this.firstTime_ = this.lastTime_ = goog.now(); - this.receivedIntermediateResult_ = false; - } - } - } -}; - - -/** - * Callback from ChannelRequest that indicates a request has completed. - * - * @param {goog.net.ChannelRequest} req The request object. - */ -goog.net.BrowserTestChannel.prototype.onRequestComplete = - function(req) { - this.lastStatusCode_ = this.request_.getLastStatusCode(); - if (!this.request_.getSuccess()) { - this.channelDebug_.debug( - 'TestConnection: request failed, in state ' + this.state_); - if (this.state_ == goog.net.BrowserTestChannel.State_.INIT) { - goog.net.BrowserChannel.notifyStatEvent( - goog.net.BrowserChannel.Stat.TEST_STAGE_ONE_FAILED); - } else if (this.state_ == - goog.net.BrowserTestChannel.State_.CONNECTION_TESTING) { - goog.net.BrowserChannel.notifyStatEvent( - goog.net.BrowserChannel.Stat.TEST_STAGE_TWO_FAILED); - } - this.channel_.testConnectionFailure(this, - /** @type {goog.net.ChannelRequest.Error} */ - (this.request_.getLastError())); - return; - } - - if (this.state_ == goog.net.BrowserTestChannel.State_.INIT) { - this.channelDebug_.debug( - 'TestConnection: request complete for initial check'); - if (this.blockedPrefix_) { - this.state_ = goog.net.BrowserTestChannel.State_.CHECKING_BLOCKED; - this.checkBlocked_(); - } else { - this.state_ = goog.net.BrowserTestChannel.State_.CONNECTION_TESTING; - this.connectStage2_(); - } - } else if (this.state_ == - goog.net.BrowserTestChannel.State_.CONNECTION_TESTING) { - this.channelDebug_.debug('TestConnection: request complete for stage 2'); - var goodConn = false; - - if (!goog.net.ChannelRequest.supportsXhrStreaming()) { - // we always get Trident responses in separate calls to - // onRequestData, so we have to check the time they came - var ms = this.lastTime_ - this.firstTime_; - if (ms < 200) { - // TODO: need to empirically verify that this number is OK - // for slow computers - goodConn = false; - } else { - goodConn = true; - } - } else { - goodConn = this.receivedIntermediateResult_; - } - - if (goodConn) { - this.channelDebug_.debug( - 'Test connection succeeded; using streaming connection'); - goog.net.BrowserChannel.notifyStatEvent( - goog.net.BrowserChannel.Stat.NOPROXY); - this.channel_.testConnectionFinished(this, true); - } else { - this.channelDebug_.debug( - 'Test connection failed; not using streaming'); - goog.net.BrowserChannel.notifyStatEvent( - goog.net.BrowserChannel.Stat.PROXY); - this.channel_.testConnectionFinished(this, false); - } - } -}; - - -/** - * Returns the last status code received for a request. - * @return {number} The last status code received for a request. - */ -goog.net.BrowserTestChannel.prototype.getLastStatusCode = function() { - return this.lastStatusCode_; -}; - - -/** - * @return {boolean} Whether we should be using secondary domains when the - * server instructs us to do so. - */ -goog.net.BrowserTestChannel.prototype.shouldUseSecondaryDomains = function() { - return this.channel_.shouldUseSecondaryDomains(); -}; - - -/** - * Gets whether this channel is currently active. This is used to determine the - * length of time to wait before retrying. - * - * @param {goog.net.BrowserChannel} browserChannel The browser channel. - * @return {boolean} Whether the channel is currently active. - */ -goog.net.BrowserTestChannel.prototype.isActive = - function(browserChannel) { - return this.channel_.isActive(); -}; - - -/** - * @return {boolean} True if test stage 2 detected a non-buffered - * channel early and early no buffering detection is enabled. - * @private - */ -goog.net.BrowserTestChannel.prototype.checkForEarlyNonBuffered_ = - function() { - var ms = this.firstTime_ - this.startTime_; - - // we always get Trident responses in separate calls to - // onRequestData, so we have to check the time that the first came in - // and verify that the data arrived before the second portion could - // have been sent. For all other browser's we skip the timing test. - return goog.net.ChannelRequest.supportsXhrStreaming() || - ms < goog.net.BrowserTestChannel.MIN_TIME_EXPECTED_BETWEEN_DATA_; -}; diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/bulkloader.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/bulkloader.js.svn-base deleted file mode 100644 index 70afa6f..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/bulkloader.js.svn-base +++ /dev/null @@ -1,172 +0,0 @@ -// Copyright 2008 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Loads a list of URIs in bulk. All requests must be a success - * in order for the load to be considered a success. - * - */ - -goog.provide('goog.net.BulkLoader'); - -goog.require('goog.debug.Logger'); -goog.require('goog.events.Event'); -goog.require('goog.events.EventHandler'); -goog.require('goog.events.EventTarget'); -goog.require('goog.net.BulkLoaderHelper'); -goog.require('goog.net.EventType'); -goog.require('goog.net.XhrIo'); - - - -/** - * Class used to load multiple URIs. - * @param {Array.<string|goog.Uri>} uris The URIs to load. - * @constructor - * @extends {goog.events.EventTarget} - */ -goog.net.BulkLoader = function(uris) { - goog.events.EventTarget.call(this); - - /** - * The bulk loader helper. - * @type {goog.net.BulkLoaderHelper} - * @private - */ - this.helper_ = new goog.net.BulkLoaderHelper(uris); - - /** - * The handler for managing events. - * @type {goog.events.EventHandler} - * @private - */ - this.eventHandler_ = new goog.events.EventHandler(this); -}; -goog.inherits(goog.net.BulkLoader, goog.events.EventTarget); - - -/** - * A logger. - * @type {goog.debug.Logger} - * @private - */ -goog.net.BulkLoader.prototype.logger_ = - goog.debug.Logger.getLogger('goog.net.BulkLoader'); - - -/** - * Gets the response texts. - * @return {Array.<string>} The response texts. - */ -goog.net.BulkLoader.prototype.getResponseTexts = function() { - return this.helper_.getResponseTexts(); -}; - - -/** - * Starts the process of loading the URIs. - */ -goog.net.BulkLoader.prototype.load = function() { - var eventHandler = this.eventHandler_; - var uris = this.helper_.getUris(); - this.logger_.info('Starting load of code with ' + uris.length + ' uris.'); - - for (var i = 0; i < uris.length; i++) { - var xhrIo = new goog.net.XhrIo(); - eventHandler.listen(xhrIo, - goog.net.EventType.COMPLETE, - goog.bind(this.handleEvent_, this, i)); - - xhrIo.send(uris[i]); - } -}; - - -/** - * Handles all events fired by the XhrManager. - * @param {number} id The id of the request. - * @param {goog.events.Event} e The event. - * @private - */ -goog.net.BulkLoader.prototype.handleEvent_ = function(id, e) { - this.logger_.info('Received event "' + e.type + '" for id ' + id + - ' with uri ' + this.helper_.getUri(id)); - var xhrIo = /** @type {goog.net.XhrIo} */ (e.target); - if (xhrIo.isSuccess()) { - this.handleSuccess_(id, xhrIo); - } else { - this.handleError_(id, xhrIo); - } -}; - - -/** - * Handles when a request is successful (i.e., completed and response received). - * Stores thhe responseText and checks if loading is complete. - * @param {number} id The id of the request. - * @param {goog.net.XhrIo} xhrIo The XhrIo objects that was used. - * @private - */ -goog.net.BulkLoader.prototype.handleSuccess_ = function( - id, xhrIo) { - // Save the response text. - this.helper_.setResponseText(id, xhrIo.getResponseText()); - - // Check if all response texts have been received. - if (this.helper_.isLoadComplete()) { - this.finishLoad_(); - } - xhrIo.dispose(); -}; - - -/** - * Handles when a request has ended in error (i.e., all retries completed and - * none were successful). Cancels loading of the URI's. - * @param {number|string} id The id of the request. - * @param {goog.net.XhrIo} xhrIo The XhrIo objects that was used. - * @private - */ -goog.net.BulkLoader.prototype.handleError_ = function( - id, xhrIo) { - // TODO(user): Abort all pending requests. - - // Dispatch the ERROR event. - this.dispatchEvent(goog.net.EventType.ERROR); - xhrIo.dispose(); -}; - - -/** - * Finishes the load of the URI's. Dispatches the SUCCESS event. - * @private - */ -goog.net.BulkLoader.prototype.finishLoad_ = function() { - this.logger_.info('All uris loaded.'); - - // Dispatch the SUCCESS event. - this.dispatchEvent(goog.net.EventType.SUCCESS); -}; - - -/** @override */ -goog.net.BulkLoader.prototype.disposeInternal = function() { - goog.net.BulkLoader.superClass_.disposeInternal.call(this); - - this.eventHandler_.dispose(); - this.eventHandler_ = null; - - this.helper_.dispose(); - this.helper_ = null; -}; diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/bulkloader_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/bulkloader_test.html.svn-base deleted file mode 100644 index 7b904fd..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/bulkloader_test.html.svn-base +++ /dev/null @@ -1,232 +0,0 @@ -<!DOCTYPE html> -<html> -<!-- -Copyright 2008 The Closure Library Authors. All Rights Reserved. - -Use of this source code is governed by the Apache License, Version 2.0. -See the COPYING file for details. ---> -<!-- ---> -<head> -<meta http-equiv="X-UA-Compatible" content="IE=edge"> -<title>Closure Unit Tests - goog.net.BulkLoader</title> -<script src="../base.js"></script> -<script> - goog.require('goog.events.EventHandler'); - goog.require('goog.net.BulkLoader'); - goog.require('goog.net.EventType'); - goog.require('goog.testing.jsunit'); - goog.require('goog.testing.MockClock'); -</script> -</head> -<body> -<script type="text/javascript"> - - /** - * Test interval between sending uri requests to the server. - */ - var DELAY_INTERVAL_BETWEEN_URI_REQUESTS = 5; - - /** - * Test interval before a response is received for a URI request. - */ - var DELAY_INTERVAL_FOR_URI_LOAD = 15; - - var clock; - var loadSuccess, loadError; - var successResponseTexts; - - function setUpPage() { - clock = new goog.testing.MockClock(true); - } - - function tearDownPage() { - clock.dispose(); - } - - function setUp() { - loadSuccess = false; - loadError = false; - successResponseTexts = []; - } - - /** - * Gets the successful bulkloader for the specified uris with some - * modifications for testability. - * <ul> - * <li> Added onSuccess methods to simulate success while loading uris. - * <li> The send function of the XhrManager used by the bulkloader - * calls the onSuccess function after a specified time interval. - * </ul> - * @param {Array.<string>} uris The URIs. - */ - function getSuccessfulBulkLoader(uris) { - var bulkLoader = new goog.net.BulkLoader(uris); - bulkLoader.load = function() { - var uris = this.helper_.getUris(); - for (var i = 0; i < uris.length; i++) { - // This clock tick simulates a delay for processing every URI. - clock.tick(DELAY_INTERVAL_BETWEEN_URI_REQUESTS); - // This timeout determines how many ticks after the send request - // all the URIs will complete loading. This delays the load of - // the first uri and every subsequent uri by 15 ticks. - setTimeout(goog.bind(this.onSuccess, this, i, uris[i]), - DELAY_INTERVAL_FOR_URI_LOAD); - } - }; - - bulkLoader.onSuccess = function(id, uri) { - var xhrIo = { - getResponseText: function() {return uri;}, - isSuccess: function() {return true;}, - dispose: function() {} - }; - this.handleEvent_(id, new goog.events.Event( - goog.net.EventType.COMPLETE, xhrIo)); - }; - - var eventHandler = new goog.events.EventHandler(); - eventHandler.listen(bulkLoader, - goog.net.EventType.SUCCESS, - handleSuccess); - eventHandler.listen(bulkLoader, - goog.net.EventType.ERROR, - handleError); - - return bulkLoader; - }; - - /** - * Gets the non-successful bulkloader for the specified uris with some - * modifications for testability. - * <ul> - * <li> Added onSuccess and onError methods to simulate success and error - * while loading uris. - * <li> The send function of the XhrManager used by the bulkloader - * calls the onSuccess or onError function after a specified time - * interval. - * </ul> - * @param {Array.<string>} uris The URIs. - */ - function getNonSuccessfulBulkLoader(uris) { - var bulkLoader = new goog.net.BulkLoader(uris); - bulkLoader.load = function() { - var uris = this.helper_.getUris(); - for (var i = 0; i < uris.length; i++) { - // This clock tick simulates a delay for processing every URI. - clock.tick(DELAY_INTERVAL_BETWEEN_URI_REQUESTS); - - // This timeout determines how many ticks after the send request - // all the URIs will complete loading in error. This delays the load - // of the first uri and every subsequent uri by 15 ticks. The URI - // with id == 2 is in error. - if (i != 2) { - setTimeout(goog.bind(this.onSuccess, this, i, uris[i]), - DELAY_INTERVAL_FOR_URI_LOAD); - } else { - setTimeout(goog.bind(this.onError, this, i, uris[i]), - DELAY_INTERVAL_FOR_URI_LOAD); - } - } - }; - - bulkLoader.onSuccess = function(id, uri) { - var xhrIo = { - getResponseText: function() {return uri;}, - isSuccess: function() {return true;}, - dispose: function() {} - }; - this.handleEvent_(id, new goog.events.Event( - goog.net.EventType.COMPLETE, xhrIo)); - }; - - bulkLoader.onError = function(id) { - var xhrIo = { - getResponseText: function() {return null;}, - isSuccess: function() {return false;}, - dispose: function() {} - }; - this.handleEvent_(id, new goog.events.Event( - goog.net.EventType.ERROR, xhrIo)); - }; - - var eventHandler = new goog.events.EventHandler(); - eventHandler.listen(bulkLoader, - goog.net.EventType.SUCCESS, - handleSuccess); - eventHandler.listen(bulkLoader, - goog.net.EventType.ERROR, - handleError); - - return bulkLoader; - }; - - function handleSuccess(e) { - loadSuccess = true; - successResponseTexts = e.target.getResponseTexts(); - } - - function handleError(e) { - loadError = true; - } - - /** - * Test successful loading of URIs using the bulkloader. - */ - function testBulkLoaderLoadSuccess() { - var uris = ['a', 'b', 'c']; - var bulkLoader = getSuccessfulBulkLoader(uris); - - bulkLoader.load(); - - clock.tick(2); - assertFalse( - 'The bulk loader is not yet loaded (after 2 ticks)', loadSuccess); - - clock.tick(3); - assertFalse( - 'The bulk loader is not yet loaded (after 5 ticks)', loadSuccess); - - clock.tick(5); - assertFalse( - 'The bulk loader is not yet loaded (after 10 ticks)', loadSuccess); - - clock.tick(5); - assertTrue('The bulk loader is loaded (after 15 ticks)', loadSuccess); - - assertArrayEquals('Ensure that the response texts are present', - successResponseTexts, uris); - } - - /** - * Test error loading URIs using the bulkloader. - */ - function testBulkLoaderLoadError() { - var uris = ['a', 'b', 'c']; - var bulkLoader = getNonSuccessfulBulkLoader(uris); - - bulkLoader.load(); - - clock.tick(2); - assertFalse( - 'The bulk loader is not yet loaded (after 2 ticks)', loadError); - - clock.tick(3); - assertFalse( - 'The bulk loader is not yet loaded (after 5 ticks)', loadError); - - clock.tick(5); - assertFalse( - 'The bulk loader is not yet loaded (after 10 ticks)', loadError); - - clock.tick(5); - assertFalse( - 'The bulk loader is not loaded successfully (after 15 ticks)', - loadSuccess); - assertTrue( - 'The bulk loader is loaded in error (after 15 ticks)', loadError); - } -</script> -</body> -</html> diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/bulkloaderhelper.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/bulkloaderhelper.js.svn-base deleted file mode 100644 index 08d7fa0..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/bulkloaderhelper.js.svn-base +++ /dev/null @@ -1,127 +0,0 @@ -// Copyright 2008 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Helper class to load a list of URIs in bulk. All URIs - * must be a successfully loaded in order for the entire load to be considered - * a success. - * - */ - -goog.provide('goog.net.BulkLoaderHelper'); - -goog.require('goog.Disposable'); -goog.require('goog.debug.Logger'); - - - -/** - * Helper class used to load multiple URIs. - * @param {Array.<string|goog.Uri>} uris The URIs to load. - * @constructor - * @extends {goog.Disposable} - */ -goog.net.BulkLoaderHelper = function(uris) { - goog.Disposable.call(this); - - /** - * The URIs to load. - * @type {Array.<string|goog.Uri>} - * @private - */ - this.uris_ = uris; - - /** - * The response from the XHR's. - * @type {Array.<string>} - * @private - */ - this.responseTexts_ = []; -}; -goog.inherits(goog.net.BulkLoaderHelper, goog.Disposable); - - -/** - * A logger. - * @type {goog.debug.Logger} - * @private - */ -goog.net.BulkLoaderHelper.prototype.logger_ = - goog.debug.Logger.getLogger('goog.net.BulkLoaderHelper'); - - -/** - * Gets the URI by id. - * @param {number} id The id. - * @return {string|goog.Uri} The URI specified by the id. - */ -goog.net.BulkLoaderHelper.prototype.getUri = function(id) { - return this.uris_[id]; -}; - - -/** - * Gets the URIs. - * @return {Array.<string|goog.Uri>} The URIs. - */ -goog.net.BulkLoaderHelper.prototype.getUris = function() { - return this.uris_; -}; - - -/** - * Gets the response texts. - * @return {Array.<string>} The response texts. - */ -goog.net.BulkLoaderHelper.prototype.getResponseTexts = function() { - return this.responseTexts_; -}; - - -/** - * Sets the response text by id. - * @param {number} id The id. - * @param {string} responseText The response texts. - */ -goog.net.BulkLoaderHelper.prototype.setResponseText = function( - id, responseText) { - this.responseTexts_[id] = responseText; -}; - - -/** - * Determines if the load of the URIs is complete. - * @return {boolean} TRUE iff the load is complete. - */ -goog.net.BulkLoaderHelper.prototype.isLoadComplete = function() { - var responseTexts = this.responseTexts_; - if (responseTexts.length == this.uris_.length) { - for (var i = 0; i < responseTexts.length; i++) { - if (!goog.isDefAndNotNull(responseTexts[i])) { - return false; - } - } - return true; - } - return false; -}; - - -/** @override */ -goog.net.BulkLoaderHelper.prototype.disposeInternal = function() { - goog.net.BulkLoaderHelper.superClass_.disposeInternal.call(this); - - this.uris_ = null; - this.responseTexts_ = null; -}; diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/channeldebug.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/channeldebug.js.svn-base deleted file mode 100644 index b31f089..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/channeldebug.js.svn-base +++ /dev/null @@ -1,287 +0,0 @@ -// Copyright 2006 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Definition of the ChannelDebug class. ChannelDebug provides - * a utility for tracing and debugging the BrowserChannel requests. - * - * TODO(user) - allow client to specify a custom redaction policy - */ - - -/** - * Namespace for BrowserChannel - */ -goog.provide('goog.net.ChannelDebug'); -goog.require('goog.debug.Logger'); -goog.require('goog.json'); - - - -/** - * Logs and keeps a buffer of debugging info for the Channel. - * - * @constructor - */ -goog.net.ChannelDebug = function() { - /** - * The logger instance. - * @type {goog.debug.Logger} - * @private - */ - this.logger_ = goog.debug.Logger.getLogger('goog.net.BrowserChannel'); -}; - - -/** - * Gets the logger used by this ChannelDebug. - * @return {goog.debug.Logger} The logger used by this ChannelDebug. - */ -goog.net.ChannelDebug.prototype.getLogger = function() { - return this.logger_; -}; - - -/** - * Logs an XmlHttp request.. - * @param {string} verb The request type (GET/POST). - * @param {goog.Uri} uri The request destination. - * @param {string|number|undefined} id The request id. - * @param {number} attempt Which attempt # the request was. - * @param {?string} postData The data posted in the request. - */ -goog.net.ChannelDebug.prototype.xmlHttpChannelRequest = - function(verb, uri, id, attempt, postData) { - this.info( - 'XMLHTTP REQ (' + id + ') [attempt ' + attempt + ']: ' + - verb + '\n' + uri + '\n' + - this.maybeRedactPostData_(postData)); -}; - - -/** - * Logs the meta data received from an XmlHttp request. - * @param {string} verb The request type (GET/POST). - * @param {goog.Uri} uri The request destination. - * @param {string|number|undefined} id The request id. - * @param {number} attempt Which attempt # the request was. - * @param {goog.net.XmlHttp.ReadyState} readyState The ready state. - * @param {number} statusCode The HTTP status code. - */ -goog.net.ChannelDebug.prototype.xmlHttpChannelResponseMetaData = - function(verb, uri, id, attempt, readyState, statusCode) { - this.info( - 'XMLHTTP RESP (' + id + ') [ attempt ' + attempt + ']: ' + - verb + '\n' + uri + '\n' + readyState + ' ' + statusCode); -}; - - -/** - * Logs the response data received from an XmlHttp request. - * @param {string|number|undefined} id The request id. - * @param {?string} responseText The response text. - * @param {?string=} opt_desc Optional request description. - */ -goog.net.ChannelDebug.prototype.xmlHttpChannelResponseText = - function(id, responseText, opt_desc) { - this.info( - 'XMLHTTP TEXT (' + id + '): ' + - this.redactResponse_(responseText) + - (opt_desc ? ' ' + opt_desc : '')); -}; - - -/** - * Logs a Trident ActiveX request. - * @param {string} verb The request type (GET/POST). - * @param {goog.Uri} uri The request destination. - * @param {string|number|undefined} id The request id. - * @param {number} attempt Which attempt # the request was. - */ -goog.net.ChannelDebug.prototype.tridentChannelRequest = - function(verb, uri, id, attempt) { - this.info( - 'TRIDENT REQ (' + id + ') [ attempt ' + attempt + ']: ' + - verb + '\n' + uri); -}; - - -/** - * Logs the response text received from a Trident ActiveX request. - * @param {string|number|undefined} id The request id. - * @param {string} responseText The response text. - */ -goog.net.ChannelDebug.prototype.tridentChannelResponseText = - function(id, responseText) { - this.info( - 'TRIDENT TEXT (' + id + '): ' + - this.redactResponse_(responseText)); -}; - - -/** - * Logs the done response received from a Trident ActiveX request. - * @param {string|number|undefined} id The request id. - * @param {boolean} successful Whether the request was successful. - */ -goog.net.ChannelDebug.prototype.tridentChannelResponseDone = - function(id, successful) { - this.info( - 'TRIDENT TEXT (' + id + '): ' + successful ? 'success' : 'failure'); -}; - - -/** - * Logs a request timeout. - * @param {goog.Uri} uri The uri that timed out. - */ -goog.net.ChannelDebug.prototype.timeoutResponse = function(uri) { - this.info('TIMEOUT: ' + uri); -}; - - -/** - * Logs a debug message. - * @param {string} text The message. - */ -goog.net.ChannelDebug.prototype.debug = function(text) { - this.info(text); -}; - - -/** - * Logs an exception - * @param {Error} e The error or error event. - * @param {string=} opt_msg The optional message, defaults to 'Exception'. - */ -goog.net.ChannelDebug.prototype.dumpException = function(e, opt_msg) { - this.severe((opt_msg || 'Exception') + e); -}; - - -/** - * Logs an info message. - * @param {string} text The message. - */ -goog.net.ChannelDebug.prototype.info = function(text) { - this.logger_.info(text); -}; - - -/** - * Logs a warning message. - * @param {string} text The message. - */ -goog.net.ChannelDebug.prototype.warning = function(text) { - this.logger_.warning(text); -}; - - -/** - * Logs a severe message. - * @param {string} text The message. - */ -goog.net.ChannelDebug.prototype.severe = function(text) { - this.logger_.severe(text); -}; - - -/** - * Removes potentially private data from a response so that we don't - * accidentally save private and personal data to the server logs. - * @param {?string} responseText A JSON response to clean. - * @return {?string} The cleaned response. - * @private - */ -goog.net.ChannelDebug.prototype.redactResponse_ = function(responseText) { - // first check if it's not JS - the only non-JS should be the magic cookie - if (!responseText || - responseText == goog.net.BrowserChannel.MAGIC_RESPONSE_COOKIE) { - return responseText; - } - /** @preserveTry */ - try { - var responseArray = goog.json.unsafeParse(responseText); - - for (var i = 0; i < responseArray.length; i++) { - if (goog.isArray(responseArray[i])) { - this.maybeRedactArray_(responseArray[i]); - } - } - - return goog.json.serialize(responseArray); - } catch (e) { - this.debug('Exception parsing expected JS array - probably was not JS'); - return responseText; - } -}; - - -/** - * Removes data from a response array that may be sensitive. - * @param {Array} array The array to clean. - * @private - */ -goog.net.ChannelDebug.prototype.maybeRedactArray_ = function(array) { - if (array.length < 2) { - return; - } - var dataPart = array[1]; - if (!goog.isArray(dataPart)) { - return; - } - if (dataPart.length < 1) { - return; - } - - var type = dataPart[0]; - if (type != 'noop' && type != 'stop') { - // redact all fields in the array - for (var i = 1; i < dataPart.length; i++) { - dataPart[i] = ''; - } - } -}; - - -/** - * Removes potentially private data from a request POST body so that we don't - * accidentally save private and personal data to the server logs. - * @param {?string} data The data string to clean. - * @return {?string} The data string with sensitive data replaced by 'redacted'. - * @private - */ -goog.net.ChannelDebug.prototype.maybeRedactPostData_ = function(data) { - if (!data) { - return null; - } - var out = ''; - var params = data.split('&'); - for (var i = 0; i < params.length; i++) { - var param = params[i]; - var keyValue = param.split('='); - if (keyValue.length > 1) { - var key = keyValue[0]; - var value = keyValue[1]; - - var keyParts = key.split('_'); - if (keyParts.length >= 2 && keyParts[1] == 'type') { - out += key + '=' + value + '&'; - } else { - out += key + '=' + 'redacted' + '&'; - } - } - } - return out; -}; diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/channelrequest.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/channelrequest.js.svn-base deleted file mode 100644 index 919962d..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/channelrequest.js.svn-base +++ /dev/null @@ -1,1139 +0,0 @@ -// Copyright 2006 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Definition of the ChannelRequest class. The ChannelRequest - * object encapsulates the logic for making a single request, either for the - * forward channel, back channel, or test channel, to the server. It contains - * the logic for the three types of transports we use in the BrowserChannel: - * XMLHTTP, Trident ActiveX (ie only), and Image request. It provides timeout - * detection. This class is part of the BrowserChannel implementation and is not - * for use by normal application code. - * - */ - - -goog.provide('goog.net.ChannelRequest'); -goog.provide('goog.net.ChannelRequest.Error'); - -goog.require('goog.Timer'); -goog.require('goog.events'); -goog.require('goog.events.EventHandler'); -goog.require('goog.net.EventType'); -goog.require('goog.net.XmlHttp.ReadyState'); -goog.require('goog.object'); -goog.require('goog.userAgent'); - - - -/** - * Creates a ChannelRequest object which encapsulates a request to the server. - * A new ChannelRequest is created for each request to the server. - * - * @param {goog.net.BrowserChannel|goog.net.BrowserTestChannel} channel - * The BrowserChannel that owns this request. - * @param {goog.net.ChannelDebug} channelDebug A ChannelDebug to use for - * logging. - * @param {string=} opt_sessionId The session id for the channel. - * @param {string|number=} opt_requestId The request id for this request. - * @param {number=} opt_retryId The retry id for this request. - * @constructor - */ -goog.net.ChannelRequest = function( - channel, channelDebug, opt_sessionId, opt_requestId, opt_retryId) { - /** - * The BrowserChannel object that owns the request. - * @type {goog.net.BrowserChannel|goog.net.BrowserTestChannel} - * @private - */ - this.channel_ = channel; - - /** - * The channel debug to use for logging - * @type {goog.net.ChannelDebug} - * @private - */ - this.channelDebug_ = channelDebug; - - /** - * The Session ID for the channel. - * @type {string|undefined} - * @private - */ - this.sid_ = opt_sessionId; - - /** - * The RID (request ID) for the request. - * @type {string|number|undefined} - * @private - */ - this.rid_ = opt_requestId; - - - /** - * The attempt number of the current request. - * @type {number} - * @private - */ - this.retryId_ = opt_retryId || 1; - - - /** - * The timeout in ms before failing the request. - * @type {number} - * @private - */ - this.timeout_ = goog.net.ChannelRequest.TIMEOUT_MS; - - /** - * An object to keep track of the channel request event listeners. - * @type {!goog.events.EventHandler} - * @private - */ - this.eventHandler_ = new goog.events.EventHandler(this); - - /** - * A timer for polling responseText in browsers that don't fire - * onreadystatechange during incremental loading of responseText. - * @type {goog.Timer} - * @private - */ - this.pollingTimer_ = new goog.Timer(); - - this.pollingTimer_.setInterval(goog.net.ChannelRequest.POLLING_INTERVAL_MS); -}; - - -/** - * Extra HTTP headers to add to all the requests sent to the server. - * @type {Object} - * @private - */ -goog.net.ChannelRequest.prototype.extraHeaders_ = null; - - -/** - * Whether the request was successful. This is only set to true after the - * request successfuly completes. - * @type {boolean} - * @private - */ -goog.net.ChannelRequest.prototype.successful_ = false; - - -/** - * The TimerID of the timer used to detect if the request has timed-out. - * @type {?number} - * @private - */ -goog.net.ChannelRequest.prototype.watchDogTimerId_ = null; - - -/** - * The time in the future when the request will timeout. - * @type {?number} - * @private - */ -goog.net.ChannelRequest.prototype.watchDogTimeoutTime_ = null; - - -/** - * The time the request started. - * @type {?number} - * @private - */ -goog.net.ChannelRequest.prototype.requestStartTime_ = null; - - -/** - * The type of request (XMLHTTP, IMG, Trident) - * @type {?number} - * @private - */ -goog.net.ChannelRequest.prototype.type_ = null; - - -/** - * The base Uri for the request. The includes all the parameters except the - * one that indicates the retry number. - * @type {goog.Uri?} - * @private - */ -goog.net.ChannelRequest.prototype.baseUri_ = null; - - -/** - * The request Uri that was actually used for the most recent request attempt. - * @type {goog.Uri?} - * @private - */ -goog.net.ChannelRequest.prototype.requestUri_ = null; - - -/** - * The post data, if the request is a post. - * @type {?string} - * @private - */ -goog.net.ChannelRequest.prototype.postData_ = null; - - -/** - * The XhrLte request if the request is using XMLHTTP - * @type {goog.net.XhrIo} - * @private - */ -goog.net.ChannelRequest.prototype.xmlHttp_ = null; - - -/** - * The position of where the next unprocessed chunk starts in the response - * text. - * @type {number} - * @private - */ -goog.net.ChannelRequest.prototype.xmlHttpChunkStart_ = 0; - - -/** - * The Trident instance if the request is using Trident. - * @type {ActiveXObject} - * @private - */ -goog.net.ChannelRequest.prototype.trident_ = null; - - -/** - * The verb (Get or Post) for the request. - * @type {?string} - * @private - */ -goog.net.ChannelRequest.prototype.verb_ = null; - - -/** - * The last error if the request failed. - * @type {?goog.net.ChannelRequest.Error} - * @private - */ -goog.net.ChannelRequest.prototype.lastError_ = null; - - -/** - * The last status code received. - * @type {number} - * @private - */ -goog.net.ChannelRequest.prototype.lastStatusCode_ = -1; - - -/** - * Whether to send the Connection:close header as part of the request. - * @type {boolean} - * @private - */ -goog.net.ChannelRequest.prototype.sendClose_ = true; - - -/** - * Whether the request has been cancelled due to a call to cancel. - * @type {boolean} - * @private - */ -goog.net.ChannelRequest.prototype.cancelled_ = false; - - -/** - * Default timeout in MS for a request. The server must return data within this - * time limit for the request to not timeout. - * @type {number} - */ -goog.net.ChannelRequest.TIMEOUT_MS = 45 * 1000; - - -/** - * How often to poll (in MS) for changes to responseText in browsers that don't - * fire onreadystatechange during incremental loading of responseText. - * @type {number} - */ -goog.net.ChannelRequest.POLLING_INTERVAL_MS = 250; - - -/** - * Minimum version of Safari that receives a non-null responseText in ready - * state interactive. - * @type {string} - * @private - */ -goog.net.ChannelRequest.MIN_WEBKIT_FOR_INTERACTIVE_ = '420+'; - - -/** - * Enum for channel requests type - * @enum {number} - * @private - */ -goog.net.ChannelRequest.Type_ = { - /** - * XMLHTTP requests. - */ - XML_HTTP: 1, - - /** - * IMG requests. - */ - IMG: 2, - - /** - * Requests that use the MSHTML ActiveX control. - */ - TRIDENT: 3 -}; - - -/** - * Enum type for identifying a ChannelRequest error. - * @enum {number} - */ -goog.net.ChannelRequest.Error = { - /** - * Errors due to a non-200 status code. - */ - STATUS: 0, - - /** - * Errors due to no data being returned. - */ - NO_DATA: 1, - - /** - * Errors due to a timeout. - */ - TIMEOUT: 2, - - /** - * Errors due to the server returning an unknown. - */ - UNKNOWN_SESSION_ID: 3, - - /** - * Errors due to bad data being received. - */ - BAD_DATA: 4, - - /** - * Errors due to the handler throwing an exception. - */ - HANDLER_EXCEPTION: 5 -}; - - -/** - * Returns a useful error string for debugging based on the specified error - * code. - * @param {goog.net.ChannelRequest.Error} errorCode The error code. - * @param {number} statusCode The HTTP status code. - * @return {string} The error string for the given code combination. - */ -goog.net.ChannelRequest.errorStringFromCode = function(errorCode, statusCode) { - switch (errorCode) { - case goog.net.ChannelRequest.Error.STATUS: - return 'Non-200 return code (' + statusCode + ')'; - case goog.net.ChannelRequest.Error.NO_DATA: - return 'XMLHTTP failure (no data)'; - case goog.net.ChannelRequest.Error.TIMEOUT: - return 'HttpConnection timeout'; - default: - return 'Unknown error'; - } -}; - - -/** - * Sentinel value used to indicate an invalid chunk in a multi-chunk response. - * @type {Object} - * @private - */ -goog.net.ChannelRequest.INVALID_CHUNK_ = {}; - - -/** - * Sentinel value used to indicate an incomplete chunk in a multi-chunk - * response. - * @type {Object} - * @private - */ -goog.net.ChannelRequest.INCOMPLETE_CHUNK_ = {}; - - -/** - * Returns whether XHR streaming is supported on this browser. - * - * If XHR streaming is not supported, we will try to use an ActiveXObject - * to create a Forever IFrame. - * - * @return {boolean} Whether XHR streaming is supported. - * @see http://code.google.com/p/closure-library/issues/detail?id=346 - */ -goog.net.ChannelRequest.supportsXhrStreaming = function() { - return !goog.userAgent.IE; -}; - - -/** - * Sets extra HTTP headers to add to all the requests sent to the server. - * - * @param {Object} extraHeaders The HTTP headers. - */ -goog.net.ChannelRequest.prototype.setExtraHeaders = function(extraHeaders) { - this.extraHeaders_ = extraHeaders; -}; - - -/** - * Sets the timeout for a request - * - * @param {number} timeout The timeout in MS for when we fail the request. - */ -goog.net.ChannelRequest.prototype.setTimeout = function(timeout) { - this.timeout_ = timeout; -}; - - -/** - * Uses XMLHTTP to send an HTTP POST to the server. - * - * @param {goog.Uri} uri The uri of the request. - * @param {string} postData The data for the post body. - * @param {boolean} decodeChunks Whether to the result is expected to be - * encoded for chunking and thus requires decoding. - */ -goog.net.ChannelRequest.prototype.xmlHttpPost = function(uri, postData, - decodeChunks) { - this.type_ = goog.net.ChannelRequest.Type_.XML_HTTP; - this.baseUri_ = uri.clone().makeUnique(); - this.postData_ = postData; - this.decodeChunks_ = decodeChunks; - this.sendXmlHttp_(null /* hostPrefix */); -}; - - -/** - * Uses XMLHTTP to send an HTTP GET to the server. - * - * @param {goog.Uri} uri The uri of the request. - * @param {boolean} decodeChunks Whether to the result is expected to be - * encoded for chunking and thus requires decoding. - * @param {?string} hostPrefix The host prefix, if we might be using a - * secondary domain. Note that it should also be in the URL, adding this - * won't cause it to be added to the URL. - * @param {boolean=} opt_noClose Whether to request that the tcp/ip connection - * should be closed. - */ -goog.net.ChannelRequest.prototype.xmlHttpGet = function(uri, decodeChunks, - hostPrefix, opt_noClose) { - this.type_ = goog.net.ChannelRequest.Type_.XML_HTTP; - this.baseUri_ = uri.clone().makeUnique(); - this.postData_ = null; - this.decodeChunks_ = decodeChunks; - if (opt_noClose) { - this.sendClose_ = false; - } - this.sendXmlHttp_(hostPrefix); -}; - - -/** - * Sends a request via XMLHTTP according to the current state of the - * ChannelRequest object. - * - * @param {?string} hostPrefix The host prefix, if we might be using a secondary - * domain. - * @private - */ -goog.net.ChannelRequest.prototype.sendXmlHttp_ = function(hostPrefix) { - this.requestStartTime_ = goog.now(); - this.ensureWatchDogTimer_(); - - // clone the base URI to create the request URI. The request uri has the - // attempt number as a parameter which helps in debugging. - this.requestUri_ = this.baseUri_.clone(); - this.requestUri_.setParameterValues('t', this.retryId_); - - // send the request either as a POST or GET - this.xmlHttpChunkStart_ = 0; - var useSecondaryDomains = this.channel_.shouldUseSecondaryDomains(); - this.xmlHttp_ = this.channel_.createXhrIo(useSecondaryDomains ? - hostPrefix : null); - goog.events.listen(this.xmlHttp_, goog.net.EventType.READY_STATE_CHANGE, - this.xmlHttpHandler_, false, this); - - var headers = this.extraHeaders_ ? goog.object.clone(this.extraHeaders_) : {}; - if (this.postData_) { - // todo (jonp) - use POST constant when Dan defines it - this.verb_ = 'POST'; - headers['Content-Type'] = 'application/x-www-form-urlencoded'; - this.xmlHttp_.send(this.requestUri_, this.verb_, this.postData_, headers); - } else { - // todo (jonp) - use GET constant when Dan defines it - this.verb_ = 'GET'; - - // If the user agent is webkit, we cannot send the close header since it is - // disallowed by the browser. If we attempt to set the "Connection: close" - // header in WEBKIT browser, it will actually causes an error message. - if (this.sendClose_ && !goog.userAgent.WEBKIT) { - headers['Connection'] = 'close'; - } - this.xmlHttp_.send(this.requestUri_, this.verb_, null, headers); - } - this.channelDebug_.xmlHttpChannelRequest(this.verb_, - this.requestUri_, this.rid_, this.retryId_, - this.postData_); -}; - - -/** - * XmlHttp handler - * @param {goog.events.Event} e Event object, target is a XhrIo object. - * @private - */ -goog.net.ChannelRequest.prototype.xmlHttpHandler_ = function(e) { - var xmlhttp = e.target; - goog.net.BrowserChannel.onStartExecution(); - /** @preserveTry */ - try { - if (xmlhttp == this.xmlHttp_) { - this.onXmlHttpReadyStateChanged_(); - } else { - this.channelDebug_.warning('Called back with an ' + - 'unexpected xmlhttp'); - } - } catch (ex) { - this.channelDebug_.debug('Failed call to OnXmlHttpReadyStateChanged_'); - if (this.xmlHttp_ && this.xmlHttp_.getResponseText()) { - this.channelDebug_.dumpException(ex, - 'ResponseText: ' + this.xmlHttp_.getResponseText()); - } else { - this.channelDebug_.dumpException(ex, 'No response text'); - } - } finally { - goog.net.BrowserChannel.onEndExecution(); - } -}; - - -/** - * Called by the readystate handler for XMLHTTP requests. - * - * @private - */ -goog.net.ChannelRequest.prototype.onXmlHttpReadyStateChanged_ = function() { - var readyState = this.xmlHttp_.getReadyState(); - // If it is Safari less than 420+, there is a bug that causes null to be - // in the responseText on ready state interactive so we must wait for - // ready state complete. - if (!goog.net.ChannelRequest.supportsXhrStreaming() || - (goog.userAgent.WEBKIT && - !goog.userAgent.isVersion( - goog.net.ChannelRequest.MIN_WEBKIT_FOR_INTERACTIVE_))) { - if (readyState < goog.net.XmlHttp.ReadyState.COMPLETE) { - // not yet ready - return; - } - } else { - // we get partial results in browsers that support ready state interactive. - // We also make sure that getResponseText is not null in interactive mode - // before we continue. However, we don't do it in Opera because it only - // fire readyState == INTERACTIVE once. We need the following code to poll - if (readyState < goog.net.XmlHttp.ReadyState.INTERACTIVE || - readyState == goog.net.XmlHttp.ReadyState.INTERACTIVE && - !goog.userAgent.OPERA && !this.xmlHttp_.getResponseText()) { - // not yet ready - return; - } - } - - // got some data so cancel the watchdog timer - this.cancelWatchDogTimer_(); - - var status = this.xmlHttp_.getStatus(); - this.lastStatusCode_ = status; - var responseText = this.xmlHttp_.getResponseText(); - if (!responseText) { - this.channelDebug_.debug('No response text for uri ' + - this.requestUri_ + ' status ' + status); - } - this.successful_ = (status == 200); - - this.channelDebug_.xmlHttpChannelResponseMetaData( - /** @type {string} */ (this.verb_), - this.requestUri_, this.rid_, this.retryId_, readyState, - status); - - if (!this.successful_) { - if (status == 400 && - responseText.indexOf('Unknown SID') > 0) { - // the server error string will include 'Unknown SID' which indicates the - // server doesn't know about the session (maybe it got restarted, maybe - // the user got moved to another server, etc.,). Handlers can special - // case this error - this.lastError_ = goog.net.ChannelRequest.Error.UNKNOWN_SESSION_ID; - goog.net.BrowserChannel.notifyStatEvent( - goog.net.BrowserChannel.Stat.REQUEST_UNKNOWN_SESSION_ID); - } else { - this.lastError_ = goog.net.ChannelRequest.Error.STATUS; - goog.net.BrowserChannel.notifyStatEvent( - goog.net.BrowserChannel.Stat.REQUEST_BAD_STATUS); - } - this.channelDebug_.xmlHttpChannelResponseText(this.rid_, responseText); - this.cleanup_(); - this.dispatchFailure_(); - return; - } - - if (readyState == goog.net.XmlHttp.ReadyState.COMPLETE) { - this.cleanup_(); - } - - if (this.decodeChunks_) { - this.decodeNextChunks_(readyState, responseText); - if (goog.userAgent.OPERA && - readyState == goog.net.XmlHttp.ReadyState.INTERACTIVE) { - this.startPolling_(); - } - } else { - this.channelDebug_.xmlHttpChannelResponseText( - this.rid_, responseText, null); - this.safeOnRequestData_(responseText); - } - - if (!this.successful_) { - return; - } - - if (!this.cancelled_) { - if (readyState == goog.net.XmlHttp.ReadyState.COMPLETE) { - this.channel_.onRequestComplete(this); - } else { - // The default is false, the result from this callback shouldn't carry - // over to the next callback, otherwise the request looks successful if - // the watchdog timer gets called - this.successful_ = false; - this.ensureWatchDogTimer_(); - } - } -}; - - -/** - * Decodes the next set of available chunks in the response. - * @param {number} readyState The value of readyState. - * @param {string} responseText The value of responseText. - * @private - */ -goog.net.ChannelRequest.prototype.decodeNextChunks_ = function(readyState, - responseText) { - var decodeNextChunksSuccessful = true; - while (!this.cancelled_ && - this.xmlHttpChunkStart_ < responseText.length) { - var chunkText = this.getNextChunk_(responseText); - if (chunkText == goog.net.ChannelRequest.INCOMPLETE_CHUNK_) { - if (readyState == goog.net.XmlHttp.ReadyState.COMPLETE) { - // should have consumed entire response when the request is done - this.lastError_ = goog.net.ChannelRequest.Error.BAD_DATA; - goog.net.BrowserChannel.notifyStatEvent( - goog.net.BrowserChannel.Stat.REQUEST_INCOMPLETE_DATA); - decodeNextChunksSuccessful = false; - } - this.channelDebug_.xmlHttpChannelResponseText( - this.rid_, null, '[Incomplete Response]'); - break; - } else if (chunkText == goog.net.ChannelRequest.INVALID_CHUNK_) { - this.lastError_ = goog.net.ChannelRequest.Error.BAD_DATA; - goog.net.BrowserChannel.notifyStatEvent( - goog.net.BrowserChannel.Stat.REQUEST_BAD_DATA); - this.channelDebug_.xmlHttpChannelResponseText( - this.rid_, responseText, '[Invalid Chunk]'); - decodeNextChunksSuccessful = false; - break; - } else { - this.channelDebug_.xmlHttpChannelResponseText( - this.rid_, /** @type {string} */ (chunkText), null); - this.safeOnRequestData_(/** @type {string} */ (chunkText)); - } - } - if (readyState == goog.net.XmlHttp.ReadyState.COMPLETE && - responseText.length == 0) { - // also an error if we didn't get any response - this.lastError_ = goog.net.ChannelRequest.Error.NO_DATA; - goog.net.BrowserChannel.notifyStatEvent( - goog.net.BrowserChannel.Stat.REQUEST_NO_DATA); - decodeNextChunksSuccessful = false; - } - this.successful_ = this.successful_ && decodeNextChunksSuccessful; - if (!decodeNextChunksSuccessful) { - // malformed response - we make this trigger retry logic - this.channelDebug_.xmlHttpChannelResponseText( - this.rid_, responseText, '[Invalid Chunked Response]'); - this.cleanup_(); - this.dispatchFailure_(); - } -}; - - -/** - * Polls the response for new data. - * @private - */ -goog.net.ChannelRequest.prototype.pollResponse_ = function() { - var readyState = this.xmlHttp_.getReadyState(); - var responseText = this.xmlHttp_.getResponseText(); - if (this.xmlHttpChunkStart_ < responseText.length) { - this.cancelWatchDogTimer_(); - this.decodeNextChunks_(readyState, responseText); - if (this.successful_ && - readyState != goog.net.XmlHttp.ReadyState.COMPLETE) { - this.ensureWatchDogTimer_(); - } - } -}; - - -/** - * Starts a polling interval for changes to responseText of the - * XMLHttpRequest, for browsers that don't fire onreadystatechange - * as data comes in incrementally. - * @private - */ -goog.net.ChannelRequest.prototype.startPolling_ = function() { - this.eventHandler_.listen(this.pollingTimer_, goog.Timer.TICK, - this.pollResponse_); - this.pollingTimer_.start(); -}; - - -/** - * Stops the polling interval for changes to responseText. - * @private - */ -goog.net.ChannelRequest.prototype.stopPolling_ = function() { - this.pollingTimer_.stop(); - this.eventHandler_.removeAll(); -}; - - -/** - * Returns the next chunk of a chunk-encoded response. This is not standard - * HTTP chunked encoding because browsers don't expose the chunk boundaries to - * the application through XMLHTTP. So we have an additional chunk encoding at - * the application level that lets us tell where the beginning and end of - * individual responses are so that we can only try to eval a complete JS array. - * - * The encoding is the size of the chunk encoded as a decimal string followed - * by a newline followed by the data. - * - * @param {string} responseText The response text from the XMLHTTP response. - * @return {string|Object} The next chunk string or a sentinel object - * indicating a special condition. - * @private - */ -goog.net.ChannelRequest.prototype.getNextChunk_ = function(responseText) { - var sizeStartIndex = this.xmlHttpChunkStart_; - var sizeEndIndex = responseText.indexOf('\n', sizeStartIndex); - if (sizeEndIndex == -1) { - return goog.net.ChannelRequest.INCOMPLETE_CHUNK_; - } - - var sizeAsString = responseText.substring(sizeStartIndex, sizeEndIndex); - var size = Number(sizeAsString); - if (isNaN(size)) { - return goog.net.ChannelRequest.INVALID_CHUNK_; - } - - var chunkStartIndex = sizeEndIndex + 1; - if (chunkStartIndex + size > responseText.length) { - return goog.net.ChannelRequest.INCOMPLETE_CHUNK_; - } - - var chunkText = responseText.substr(chunkStartIndex, size); - this.xmlHttpChunkStart_ = chunkStartIndex + size; - return chunkText; -}; - - -/** - * Uses the Trident htmlfile ActiveX control to send a GET request in IE. This - * is the innovation discovered that lets us get intermediate results in - * Internet Explorer. Thanks to http://go/kev - * @param {goog.Uri} uri The uri to request from. - * @param {boolean} usingSecondaryDomain Whether to use a secondary domain. - */ -goog.net.ChannelRequest.prototype.tridentGet = function(uri, - usingSecondaryDomain) { - this.type_ = goog.net.ChannelRequest.Type_.TRIDENT; - this.baseUri_ = uri.clone().makeUnique(); - this.tridentGet_(usingSecondaryDomain); -}; - - -/** - * Starts the Trident request. - * @param {boolean} usingSecondaryDomain Whether to use a secondary domain. - * @private - */ -goog.net.ChannelRequest.prototype.tridentGet_ = function(usingSecondaryDomain) { - this.requestStartTime_ = goog.now(); - this.ensureWatchDogTimer_(); - - this.trident_ = new ActiveXObject('htmlfile'); - - var hostname = ''; - var body = '<html><body>'; - if (usingSecondaryDomain) { - hostname = window.location.hostname; - body += '<script>document.domain="' + hostname + '"</scr' + 'ipt>'; - } - body += '</body></html>'; - - this.trident_.open(); - this.trident_.write(body); - this.trident_.close(); - - this.trident_.parentWindow['m'] = goog.bind(this.onTridentRpcMessage_, this); - this.trident_.parentWindow['d'] = goog.bind(this.onTridentDone_, this, true); - this.trident_.parentWindow['rpcClose'] = - goog.bind(this.onTridentDone_, this, false); - - var div = this.trident_.createElement('div'); - this.trident_.parentWindow.document.body.appendChild(div); - this.requestUri_ = this.baseUri_.clone(); - this.requestUri_.setParameterValue('DOMAIN', hostname); - this.requestUri_.setParameterValue('t', this.retryId_); - div.innerHTML = '<iframe src="' + this.requestUri_ + '"></iframe>'; - this.channelDebug_.tridentChannelRequest('GET', - this.requestUri_, this.rid_, this.retryId_); -}; - - -/** - * Callback from the Trident htmlfile ActiveX control for when a new message - * is received. - * - * @param {string} msg The data payload. - * @private - */ -goog.net.ChannelRequest.prototype.onTridentRpcMessage_ = function(msg) { - // need to do async b/c this gets called off of the context of the ActiveX - goog.net.BrowserChannel.setTimeout( - goog.bind(this.onTridentRpcMessageAsync_, this, msg), 0); -}; - - -/** - * Callback from the Trident htmlfile ActiveX control for when a new message - * is received. - * - * @param {string} msg The data payload. - * @private - */ -goog.net.ChannelRequest.prototype.onTridentRpcMessageAsync_ = function(msg) { - if (this.cancelled_) { - return; - } - this.channelDebug_.tridentChannelResponseText(this.rid_, msg); - this.cancelWatchDogTimer_(); - this.safeOnRequestData_(msg); - this.ensureWatchDogTimer_(); -}; - - -/** - * Callback from the Trident htmlfile ActiveX control for when the request - * is complete - * - * @param {boolean} successful Whether the request successfully completed. - * @private - */ -goog.net.ChannelRequest.prototype.onTridentDone_ = function(successful) { - // need to do async b/c this gets called off of the context of the ActiveX - goog.net.BrowserChannel.setTimeout( - goog.bind(this.onTridentDoneAsync_, this, successful), 0); -}; - - -/** - * Callback from the Trident htmlfile ActiveX control for when the request - * is complete - * - * @param {boolean} successful Whether the request successfully completed. - * @private - */ -goog.net.ChannelRequest.prototype.onTridentDoneAsync_ = function(successful) { - if (this.cancelled_) { - return; - } - this.channelDebug_.tridentChannelResponseDone( - this.rid_, successful); - this.cancelWatchDogTimer_(); - this.cleanup_(); - this.successful_ = successful; - this.channel_.onRequestComplete(this); -}; - - -/** - * Uses an IMG tag to send an HTTP get to the server. This is only currently - * used to terminate the connection, as an IMG tag is the most reliable way to - * send something to the server while the page is getting torn down. - * @param {goog.Uri} uri The uri to send a request to. - */ -goog.net.ChannelRequest.prototype.sendUsingImgTag = function(uri) { - this.type_ = goog.net.ChannelRequest.Type_.IMG; - this.baseUri_ = uri.clone().makeUnique(); - this.imgTagGet_(); -}; - - -/** - * Starts the IMG request. - * - * @private - */ -goog.net.ChannelRequest.prototype.imgTagGet_ = function() { - var eltImg = new Image(); - eltImg.src = this.baseUri_; - this.requestStartTime_ = goog.now(); - this.ensureWatchDogTimer_(); -}; - - -/** - * Cancels the request no matter what the underlying transport is. - */ -goog.net.ChannelRequest.prototype.cancel = function() { - this.cancelled_ = true; - this.cancelWatchDogTimer_(); - this.cleanup_(); -}; - - -/** - * Ensures that there is watchdog timeout which is used to ensure that - * the connection completes in time. - * - * @private - */ -goog.net.ChannelRequest.prototype.ensureWatchDogTimer_ = function() { - this.watchDogTimeoutTime_ = goog.now() + this.timeout_; - this.startWatchDogTimer_(this.timeout_); -}; - - -/** - * Starts the watchdog timer which is used to ensure that the connection - * completes in time. - * @param {number} time The number of milliseconds to wait. - * @private - */ -goog.net.ChannelRequest.prototype.startWatchDogTimer_ = function(time) { - if (this.watchDogTimerId_ != null) { - // assertion - throw Error('WatchDog timer not null'); - } - this.watchDogTimerId_ = goog.net.BrowserChannel.setTimeout( - goog.bind(this.onWatchDogTimeout_, this), time); -}; - - -/** - * Cancels the watchdog timer if it has been started. - * - * @private - */ -goog.net.ChannelRequest.prototype.cancelWatchDogTimer_ = function() { - if (this.watchDogTimerId_) { - goog.global.clearTimeout(this.watchDogTimerId_); - this.watchDogTimerId_ = null; - } -}; - - -/** - * Called when the watchdog timer is triggered. It also handles a case where it - * is called too early which we suspect may be happening sometimes - * (not sure why) - * - * @private - */ -goog.net.ChannelRequest.prototype.onWatchDogTimeout_ = function() { - this.watchDogTimerId_ = null; - var now = goog.now(); - if (now - this.watchDogTimeoutTime_ >= 0) { - this.handleTimeout_(); - } else { - // got called too early for some reason - this.channelDebug_.warning('WatchDog timer called too early'); - this.startWatchDogTimer_(this.watchDogTimeoutTime_ - now); - } -}; - - -/** - * Called when the request has actually timed out. Will cleanup and notify the - * channel of the failure. - * - * @private - */ -goog.net.ChannelRequest.prototype.handleTimeout_ = function() { - if (this.successful_) { - // Should never happen. - this.channelDebug_.severe( - 'Received watchdog timeout even though request loaded successfully'); - } - - this.channelDebug_.timeoutResponse(this.requestUri_); - this.cleanup_(); - - // set error and dispatch failure - this.lastError_ = goog.net.ChannelRequest.Error.TIMEOUT; - goog.net.BrowserChannel.notifyStatEvent( - goog.net.BrowserChannel.Stat.REQUEST_TIMEOUT); - this.dispatchFailure_(); -}; - - -/** - * Notifies the channel that this request failed. - * @private - */ -goog.net.ChannelRequest.prototype.dispatchFailure_ = function() { - if (this.channel_.isClosed() || this.cancelled_) { - return; - } - - this.channel_.onRequestComplete(this); -}; - - -/** - * Cleans up the objects used to make the request. This function is - * idempotent. - * - * @private - */ -goog.net.ChannelRequest.prototype.cleanup_ = function() { - this.stopPolling_(); - if (this.xmlHttp_) { - // clear out this.xmlHttp_ before aborting so we handle getting reentered - // inside abort - var xmlhttp = this.xmlHttp_; - this.xmlHttp_ = null; - goog.events.unlisten(xmlhttp, goog.net.EventType.READY_STATE_CHANGE, - this.xmlHttpHandler_, false, this); - xmlhttp.abort(); - } - - if (this.trident_) { - this.trident_ = null; - } -}; - - -/** - * Indicates whether the request was successful. Only valid after the handler - * is called to indicate completion of the request. - * - * @return {boolean} True if the request succeeded. - */ -goog.net.ChannelRequest.prototype.getSuccess = function() { - return this.successful_; -}; - - -/** - * If the request was not successful, returns the reason. - * - * @return {?goog.net.ChannelRequest.Error} The last error. - */ -goog.net.ChannelRequest.prototype.getLastError = function() { - return this.lastError_; -}; - - -/** - * Returns the status code of the last request. - * @return {number} The status code of the last request. - */ -goog.net.ChannelRequest.prototype.getLastStatusCode = function() { - return this.lastStatusCode_; -}; - - -/** - * Returns the session id for this channel. - * - * @return {string|undefined} The session ID. - */ -goog.net.ChannelRequest.prototype.getSessionId = function() { - return this.sid_; -}; - - -/** - * Returns the request id for this request. Each request has a unique request - * id and the request IDs are a sequential increasing count. - * - * @return {string|number|undefined} The request ID. - */ -goog.net.ChannelRequest.prototype.getRequestId = function() { - return this.rid_; -}; - - -/** - * Returns the data for a post, if this request is a post. - * - * @return {?string} The POST data provided by the request initiator. - */ -goog.net.ChannelRequest.prototype.getPostData = function() { - return this.postData_; -}; - - -/** - * Returns the time that the request started, if it has started. - * - * @return {?number} The time the request started, as returned by goog.now(). - */ -goog.net.ChannelRequest.prototype.getRequestStartTime = function() { - return this.requestStartTime_; -}; - - -/** - * Helper to call the callback's onRequestData, which catches any - * exception and cleans up the request. - * @param {string} data The request data. - * @private - */ -goog.net.ChannelRequest.prototype.safeOnRequestData_ = function(data) { - /** @preserveTry */ - try { - this.channel_.onRequestData(this, data); - } catch (e) { - // Dump debug info, but keep going without closing the channel. - this.channelDebug_.dumpException( - e, 'Error in httprequest callback'); - } -}; diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/channelrequest_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/channelrequest_test.html.svn-base deleted file mode 100644 index 1bca491..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/channelrequest_test.html.svn-base +++ /dev/null @@ -1,187 +0,0 @@ -<!DOCTYPE html> -<html> -<!-- -Copyright 2008 The Closure Library Authors. All Rights Reserved. - -Use of this source code is governed by the Apache License, Version 2.0. -See the COPYING file for details. ---> -<!-- ---> -<head> -<meta http-equiv="X-UA-Compatible" content="IE=edge"> -<title>Closure Unit Tests - goog.net.ChannelRequest</title> -<script src="../base.js"></script> -<script> -goog.require('goog.functions'); -goog.require('goog.net.BrowserChannel'); -goog.require('goog.net.ChannelDebug'); -goog.require('goog.net.ChannelRequest'); -goog.require('goog.testing.MockClock'); -goog.require('goog.testing.jsunit'); -goog.require('goog.testing.net.XhrIo'); -</script> -</head> -<body> -<script> - -var mockClock; - -/** - * Time to wait for a network request to time out, before aborting. - */ -var WATCHDOG_TIME = 2000; - -/** - * A really long time - used to make sure no more timeouts will fire. - */ -var ALL_DAY_MS = 1000 * 60 * 60 * 24; - - -function setUp() { - mockClock = new goog.testing.MockClock(); - mockClock.install(); -} - - -function tearDown() { - mockClock.uninstall(); -} - - -/** - * Constructs a duck-type BrowserChannel that tracks the completed requests. - * @constructor - */ -function MockBrowserChannel() { - this.createXhrIo = function(domainPrefix) { - assertNull(domainPrefix); - var xhrIo = new goog.testing.net.XhrIo(); - xhrIo.abort = xhrIo.abort || function() { - this.active_ = false; - }; - return xhrIo; - } - this.isClosed = function() { - return false; - }; - this.isActive = function() { - return true; - }; - this.shouldUseSecondaryDomains = function() { - return false; - } - this.completedRequests = []; - this.onRequestComplete = function(request) { - this.completedRequests.push(request); - }; - this.onRequestData = function(request, data) {}; -} - - -/** - * Creates a real ChannelRequest object, with some modifications for - * testability: - * <ul> - * <li>The BrowserChannel is a MockBrowserChannel. - * <li>createXhrIo_() returns the xhrIo that is passed in. - * <li>The new watchdogTimeoutCallCount property tracks onWatchDogTimeout_() - * calls. - * <li>The timeout is set to WATCHDOG_TIME. - * </ul> - * @param {goog.testing.net.XhrIo} xhrIo A test XhrIo. - * @return {goog.net.ChannelRequest} A slightly modified ChannelRequest - */ -function createChannelRequest(xhrIo) { - // Install mock browser channel and no-op debug logger. - var req = new goog.net.ChannelRequest( - new MockBrowserChannel(), - new goog.net.ChannelDebug()); - - // Install test XhrIo. - req.createXhrIo_ = function() { - return xhrIo; - }; - - // Install watchdogTimeoutCallCount. - req.watchdogTimeoutCallCount = 0; - req.originalOnWatchDogTimeout = req.onWatchDogTimeout_; - req.onWatchDogTimeout_ = function() { - this.watchdogTimeoutCallCount++; - return this.originalOnWatchDogTimeout(); - }; - - req.setTimeout(WATCHDOG_TIME); - - return req; -} - - -/** - * Creates a test XhrIo, with the abort() method defined. - * @return {goog.testing.net.XhrIo} A test XhrIo. - */ -function createXhrIo() { - var xhrIo = new goog.testing.net.XhrIo(); - xhrIo.abort = xhrIo.abort || function() { - this.active_ = false; - }; - return xhrIo; -} - - -/** - * Make sure that the request "completes" with an error when the timeout - * expires. - */ -function testRequestTimeout() { - var xhrIo = createXhrIo(); - var req = createChannelRequest(xhrIo); - - req.xmlHttpPost(new goog.Uri('some_uri'), 'some_postdata', true); - assertEquals(0, req.watchdogTimeoutCallCount); - assertEquals(0, req.channel_.completedRequests.length); - - // Watchdog timeout. - mockClock.tick(WATCHDOG_TIME); - assertEquals(1, req.watchdogTimeoutCallCount); - assertEquals(1, req.channel_.completedRequests.length); - assertFalse(req.getSuccess()); - - // Make sure no more timers are firing. - mockClock.tick(ALL_DAY_MS); - assertEquals(1, req.watchdogTimeoutCallCount); - assertEquals(1, req.channel_.completedRequests.length); -} - -function testRequestTimeoutWithUnexpectedException() { - var xhrIo = createXhrIo(); - var req = createChannelRequest(xhrIo); - req.channel_.createXhrIo = goog.functions.error('Weird error'); - - try { - req.xmlHttpGet(new goog.Uri('some_uri'), true, null); - fail('Expected error'); - } catch (e) { - assertEquals('Weird error', e.message); - } - - - assertEquals(0, req.watchdogTimeoutCallCount); - assertEquals(0, req.channel_.completedRequests.length); - - // Watchdog timeout. - mockClock.tick(WATCHDOG_TIME); - assertEquals(1, req.watchdogTimeoutCallCount); - assertEquals(1, req.channel_.completedRequests.length); - assertFalse(req.getSuccess()); - - // Make sure no more timers are firing. - mockClock.tick(ALL_DAY_MS); - assertEquals(1, req.watchdogTimeoutCallCount); - assertEquals(1, req.channel_.completedRequests.length); -} - -</script> -</body> -</html> diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/cookies.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/cookies.js.svn-base deleted file mode 100644 index 9978f27..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/cookies.js.svn-base +++ /dev/null @@ -1,402 +0,0 @@ -// Copyright 2006 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Functions for setting, getting and deleting cookies. - * - * @author arv@google.com (Erik Arvidsson) - */ - - -goog.provide('goog.net.Cookies'); -goog.provide('goog.net.cookies'); - -goog.require('goog.userAgent'); - - - -/** - * A class for handling browser cookies. - * @param {Document} context The context document to get/set cookies on. - * @constructor - */ -goog.net.Cookies = function(context) { - /** - * The context document to get/set cookies on - * @type {Document} - * @private - */ - this.document_ = context; -}; - - -/** - * Static constant for the size of cookies. Per the spec, there's a 4K limit - * to the size of a cookie. To make sure users can't break this limit, we - * should truncate long cookies at 3950 bytes, to be extra careful with dumb - * browsers/proxies that interpret 4K as 4000 rather than 4096. - * @type {number} - */ -goog.net.Cookies.MAX_COOKIE_LENGTH = 3950; - - -/** - * RegExp used to split the cookies string. - * @type {RegExp} - * @private - */ -goog.net.Cookies.SPLIT_RE_ = /\s*;\s*/; - - -/** - * Test cookie name. Used for a temp cookie when testing if cookies are - * enabled. - * @type {string} - * @private - */ -goog.net.Cookies.TEST_COOKIE_NAME_ = 'COOKIES_TEST_'; - - -/** - * Returns true if cookies are enabled. - * @return {boolean} True if cookies are enabled. - */ -goog.net.Cookies.prototype.isEnabled = function() { - var isEnabled = this.isNavigatorCookieEnabled_(); - - if (isEnabled && goog.userAgent.WEBKIT) { - // Chrome has a bug where it will report cookies as enabled even if they - // are not, see http://code.google.com/p/chromium/issues/detail?id=1850 . - // To work around, we set a unique cookie, then check for it. - var cookieName = goog.net.Cookies.TEST_COOKIE_NAME_ + goog.now(); - goog.net.cookies.set(cookieName, '1'); - if (!this.get(cookieName)) { - return false; - } - // Remove temp cookie. - this.remove(cookieName); - } - - return isEnabled; -}; - - -/** - * We do not allow '=', ';', or white space in the name. - * - * NOTE: The following are allowed by this method, but should be avoided for - * cookies handled by the server. - * - any name starting with '$' - * - 'Comment' - * - 'Domain' - * - 'Expires' - * - 'Max-Age' - * - 'Path' - * - 'Secure' - * - 'Version' - * - * @param {string} name Cookie name. - * @return {boolean} Whether name is valid. - * - * @see <a href="http://tools.ietf.org/html/rfc2109">RFC 2109</a> - * @see <a href="http://tools.ietf.org/html/rfc2965">RFC 2965</a> - */ -goog.net.Cookies.prototype.isValidName = function(name) { - return !(/[;=\s]/.test(name)); -}; - - -/** - * We do not allow ';' or line break in the value. - * - * Spec does not mention any illegal characters, but in practice semi-colons - * break parsing and line breaks truncate the name. - * - * @param {string} value Cookie value. - * @return {boolean} Whether value is valid. - * - * @see <a href="http://tools.ietf.org/html/rfc2109">RFC 2109</a> - * @see <a href="http://tools.ietf.org/html/rfc2965">RFC 2965</a> - */ -goog.net.Cookies.prototype.isValidValue = function(value) { - return !(/[;\r\n]/.test(value)); -}; - - -/** - * Sets a cookie. The max_age can be -1 to set a session cookie. To remove and - * expire cookies, use remove() instead. - * - * Neither the {@code name} nor the {@code value} are encoded in any way. It is - * up to the callers of {@code get} and {@code set} (as well as all the other - * methods) to handle any possible encoding and decoding. - * - * @throws {!Error} If the {@code name} fails #goog.net.cookies.isValidName. - * @throws {!Error} If the {@code value} fails #goog.net.cookies.isValidValue. - * - * @param {string} name The cookie name. - * @param {string} value The cookie value. - * @param {number=} opt_maxAge The max age in seconds (from now). Use -1 to - * set a session cookie. If not provided, the default is -1 - * (i.e. set a session cookie). - * @param {?string=} opt_path The path of the cookie. If not present then this - * uses the full request path. - * @param {?string=} opt_domain The domain of the cookie, or null to not - * specify a domain attribute (browser will use the full request host name). - * If not provided, the default is null (i.e. let browser use full request - * host name). - * @param {boolean=} opt_secure Whether the cookie should only be sent over - * a secure channel. - */ -goog.net.Cookies.prototype.set = function( - name, value, opt_maxAge, opt_path, opt_domain, opt_secure) { - if (!this.isValidName(name)) { - throw Error('Invalid cookie name "' + name + '"'); - } - if (!this.isValidValue(value)) { - throw Error('Invalid cookie value "' + value + '"'); - } - - if (!goog.isDef(opt_maxAge)) { - opt_maxAge = -1; - } - - var domainStr = opt_domain ? ';domain=' + opt_domain : ''; - var pathStr = opt_path ? ';path=' + opt_path : ''; - var secureStr = opt_secure ? ';secure' : ''; - - var expiresStr; - - // Case 1: Set a session cookie. - if (opt_maxAge < 0) { - expiresStr = ''; - - // Case 2: Expire the cookie. - // Note: We don't tell people about this option in the function doc because - // we prefer people to use ExpireCookie() to expire cookies. - } else if (opt_maxAge == 0) { - // Note: Don't use Jan 1, 1970 for date because NS 4.76 will try to convert - // it to local time, and if the local time is before Jan 1, 1970, then the - // browser will ignore the Expires attribute altogether. - var pastDate = new Date(1970, 1 /*Feb*/, 1); // Feb 1, 1970 - expiresStr = ';expires=' + pastDate.toUTCString(); - - // Case 3: Set a persistent cookie. - } else { - var futureDate = new Date(goog.now() + opt_maxAge * 1000); - expiresStr = ';expires=' + futureDate.toUTCString(); - } - - this.setCookie_(name + '=' + value + domainStr + pathStr + - expiresStr + secureStr); -}; - - -/** - * Returns the value for the first cookie with the given name. - * @param {string} name The name of the cookie to get. - * @param {string=} opt_default If not found this is returned instead. - * @return {string|undefined} The value of the cookie. If no cookie is set this - * returns opt_default or undefined if opt_default is not provided. - */ -goog.net.Cookies.prototype.get = function(name, opt_default) { - var nameEq = name + '='; - var parts = this.getParts_(); - for (var i = 0, part; part = parts[i]; i++) { - if (part.indexOf(nameEq) == 0) { - return part.substr(nameEq.length); - } - } - return opt_default; -}; - - -/** - * Removes and expires a cookie. - * @param {string} name The cookie name. - * @param {string=} opt_path The path of the cookie, or null to expire a cookie - * set at the full request path. If not provided, the default is '/' - * (i.e. path=/). - * @param {string=} opt_domain The domain of the cookie, or null to expire a - * cookie set at the full request host name. If not provided, the default is - * null (i.e. cookie at full request host name). - * @return {boolean} Whether the cookie existed before it was removed. - */ -goog.net.Cookies.prototype.remove = function(name, opt_path, opt_domain) { - var rv = this.containsKey(name); - this.set(name, '', 0, opt_path, opt_domain); - return rv; -}; - - -/** - * Gets the names for all the cookies. - * @return {Array.<string>} An array with the names of the cookies. - */ -goog.net.Cookies.prototype.getKeys = function() { - return this.getKeyValues_().keys; -}; - - -/** - * Gets the values for all the cookies. - * @return {Array.<string>} An array with the values of the cookies. - */ -goog.net.Cookies.prototype.getValues = function() { - return this.getKeyValues_().values; -}; - - -/** - * @return {boolean} Whether there are any cookies for this document. - */ -goog.net.Cookies.prototype.isEmpty = function() { - return !this.getCookie_(); -}; - - -/** - * @return {number} The number of cookies for this document. - */ -goog.net.Cookies.prototype.getCount = function() { - var cookie = this.getCookie_(); - if (!cookie) { - return 0; - } - return this.getParts_().length; -}; - - -/** - * Returns whether there is a cookie with the given name. - * @param {string} key The name of the cookie to test for. - * @return {boolean} Whether there is a cookie by that name. - */ -goog.net.Cookies.prototype.containsKey = function(key) { - // substring will return empty string if the key is not found, so the get - // function will only return undefined - return goog.isDef(this.get(key)); -}; - - -/** - * Returns whether there is a cookie with the given value. (This is an O(n) - * operation.) - * @param {string} value The value to check for. - * @return {boolean} Whether there is a cookie with that value. - */ -goog.net.Cookies.prototype.containsValue = function(value) { - // this O(n) in any case so lets do the trivial thing. - var values = this.getKeyValues_().values; - for (var i = 0; i < values.length; i++) { - if (values[i] == value) { - return true; - } - } - return false; -}; - - -/** - * Removes all cookies for this document. Note that this will only remove - * cookies from the current path and domain. If there are cookies set using a - * subpath and/or another domain these will still be there. - */ -goog.net.Cookies.prototype.clear = function() { - var keys = this.getKeyValues_().keys; - for (var i = keys.length - 1; i >= 0; i--) { - this.remove(keys[i]); - } -}; - - -/** - * Private helper function to allow testing cookies without depending on the - * browser. - * @param {string} s The cookie string to set. - * @private - */ -goog.net.Cookies.prototype.setCookie_ = function(s) { - this.document_.cookie = s; -}; - - -/** - * Private helper function to allow testing cookies without depending on the - * browser. IE6 can return null here. - * @return {?string} Returns the {@code document.cookie}. - * @private - */ -goog.net.Cookies.prototype.getCookie_ = function() { - return this.document_.cookie; -}; - - -/** - * @return {!Array.<string>} The cookie split on semi colons. - * @private - */ -goog.net.Cookies.prototype.getParts_ = function() { - return (this.getCookie_() || ''). - split(goog.net.Cookies.SPLIT_RE_); -}; - - -/** - * Returns navigator.cookieEnabled. Overridden in unit tests. - * @return {boolean} The value of navigator.cookieEnabled. - * @private - */ -goog.net.Cookies.prototype.isNavigatorCookieEnabled_ = function() { - return navigator.cookieEnabled; -}; - - -/** - * Gets the names and values for all the cookies. - * @return {Object} An object with keys and values. - * @private - */ -goog.net.Cookies.prototype.getKeyValues_ = function() { - var parts = this.getParts_(); - var keys = [], values = [], index, part; - for (var i = 0; part = parts[i]; i++) { - index = part.indexOf('='); - - if (index == -1) { // empty name - keys.push(''); - values.push(part); - } else { - keys.push(part.substring(0, index)); - values.push(part.substring(index + 1)); - } - } - return {keys: keys, values: values}; -}; - - -/** - * A static default instance. - * @type {goog.net.Cookies} - */ -goog.net.cookies = new goog.net.Cookies(document); - - -/** - * Define the constant on the instance in order not to break many references to - * it. - * @type {number} - * @deprecated Use goog.net.Cookies.MAX_COOKIE_LENGTH instead. - */ -goog.net.cookies.MAX_COOKIE_LENGTH = goog.net.Cookies.MAX_COOKIE_LENGTH; diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/cookies_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/cookies_test.html.svn-base deleted file mode 100644 index 10ec66c..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/cookies_test.html.svn-base +++ /dev/null @@ -1,255 +0,0 @@ -<!DOCTYPE html> -<html> -<!-- -Copyright 2006 The Closure Library Authors. All Rights Reserved. - -Use of this source code is governed by the Apache License, Version 2.0. -See the COPYING file for details. ---> -<head> -<meta http-equiv="X-UA-Compatible" content="IE=edge"> -<title>Closure Unit Tests - goog.net.cookies</title> -<script src="../base.js"></script> -<script> - goog.require('goog.array'); - goog.require('goog.net.cookies'); - goog.require('goog.testing.jsunit'); -</script> -</head> -<body> -<script> - -var cookies = goog.net.cookies; -var baseCount = 0; - -function checkForCookies() { - if (!cookies.isEnabled()) { - var message = 'Cookies must be enabled to run this test.'; - if (location.protocol == 'file:') { - message += '\nNote that cookies for local files are disabled in some ' + - 'browsers.\nThey can be enabled in Chrome with the ' + - '--enable-file-cookies flag.'; - } - - fail(message); - } -} - -function setUp() { - checkForCookies(); - - // Make sure there are no cookies set by previous, bad tests. - cookies.clear(); - baseCount = cookies.getCount(); -} - -function tearDown() { - // Clear up after ourselves. - cookies.clear(); -} - -function testIsEnabled() { - // Save static function prior to mocking. - var isNavigatorCookieEnabled = cookies.isNavigatorCookieEnabled_; - try { - cookies.isNavigatorCookieEnabled_ = function() { return true; }; - assertTrue(cookies.isEnabled()); - cookies.isNavigatorCookieEnabled_ = function() { return false; }; - assertFalse(cookies.isEnabled()); - } finally { - // Restore static function. - cookies.isNavigatorCookieEnabled_ = isNavigatorCookieEnabled; - } -} - -function testCount() { - // setUp empties the cookies - - cookies.set('testa', 'A'); - assertEquals(baseCount + 1, cookies.getCount()); - cookies.set('testb', 'B'); - cookies.set('testc', 'C'); - assertEquals(baseCount + 3, cookies.getCount()); - cookies.remove('testa'); - cookies.remove('testb'); - assertEquals(baseCount + 1, cookies.getCount()); - cookies.remove('testc'); - assertEquals(baseCount + 0, cookies.getCount()); -} - -function testSet() { - cookies.set('testa', 'testb'); - assertEquals('testb', cookies.get('testa')); - cookies.remove('testa'); - assertEquals(undefined, cookies.get('testa')); - // check for invalid characters in name and value -} - -function testGetKeys() { - cookies.set('testa', 'A'); - cookies.set('testb', 'B'); - cookies.set('testc', 'C'); - var keys = cookies.getKeys(); - assertTrue(goog.array.contains(keys, 'testa')); - assertTrue(goog.array.contains(keys, 'testb')); - assertTrue(goog.array.contains(keys, 'testc')); -} - - -function testGetValues() { - cookies.set('testa', 'A'); - cookies.set('testb', 'B'); - cookies.set('testc', 'C'); - var values = cookies.getValues(); - assertTrue(goog.array.contains(values, 'A')); - assertTrue(goog.array.contains(values, 'B')); - assertTrue(goog.array.contains(values, 'C')); -} - - -function testContainsKey() { - assertFalse(cookies.containsKey('testa')); - cookies.set('testa', 'A'); - assertTrue(cookies.containsKey('testa')); - cookies.set('testb', 'B'); - assertTrue(cookies.containsKey('testb')); - cookies.remove('testb'); - assertFalse(cookies.containsKey('testb')); - cookies.remove('testa'); - assertFalse(cookies.containsKey('testa')); -} - - -function testContainsValue() { - assertFalse(cookies.containsValue('A')); - cookies.set('testa', 'A'); - assertTrue(cookies.containsValue('A')); - cookies.set('testb', 'B'); - assertTrue(cookies.containsValue('B')); - cookies.remove('testb'); - assertFalse(cookies.containsValue('B')); - cookies.remove('testa'); - assertFalse(cookies.containsValue('A')); -} - - -function testIsEmpty() { - // we cannot guarantee that we have no cookies so testing for the true - // case cannot be done without a mock document.cookie - cookies.set('testa', 'A'); - assertFalse(cookies.isEmpty()); - cookies.set('testb', 'B'); - assertFalse(cookies.isEmpty()); - cookies.remove('testb'); - assertFalse(cookies.isEmpty()); - cookies.remove('testa'); -} - - -function testRemove() { - assertFalse('1. Cookie should not contain "testa"', cookies.containsKey('testa')); - cookies.set('testa', 'A', undefined, '/'); - assertTrue('2. Cookie should contain "testa"', cookies.containsKey('testa')); - cookies.remove('testa', '/'); - assertFalse('3. Cookie should not contain "testa"', cookies.containsKey('testa')); - - cookies.set('testa', 'A'); - assertTrue('4. Cookie should contain "testa"', cookies.containsKey('testa')); - cookies.remove('testa'); - assertFalse('5. Cookie should not contain "testa"', cookies.containsKey('testa')); -} - -function testStrangeValue() { - // This ensures that the pattern key2=value in the value does not match - // the key2 cookie. - var value = 'testb=bbb'; - var value2 = 'ccc'; - - cookies.set('testa', value); - cookies.set('testb', value2); - - assertEquals(value, cookies.get('testa')); - assertEquals(value2, cookies.get('testb')); -} - -function testSetCookiePath() { - assertEquals('foo=bar;path=/xyz', - mockSetCookie('foo', 'bar', -1, '/xyz')); -} - -function testSetCookieDomain() { - assertEquals('foo=bar;domain=google.com', - mockSetCookie('foo', 'bar', -1, null, 'google.com')); -} - -function testSetCookieSecure() { - assertEquals('foo=bar;secure', - mockSetCookie('foo', 'bar', -1, null, null, true)); -} - -function testSetCookieMaxAgeZero() { - var result = mockSetCookie('foo', 'bar', 0); - var pattern = new RegExp( - 'foo=bar;expires=' + new Date(1970, 1, 1).toUTCString()); - if (!result.match(pattern)) { - fail('expected match against ' + pattern + ' got ' + result); - } -} - -// TODO(chrisn): Testing max age > 0 requires a mock clock. - -function mockSetCookie(var_args) { - var setCookie = cookies.setCookie_; - try { - var result; - cookies.setCookie_ = function(arg) { - result = arg; - }; - cookies.set.apply(cookies, arguments); - return result; - } finally { - cookies.setCookie_ = setCookie; - } -} - -function assertValidName(name) { - assertTrue(name + ' should be valid', cookies.isValidName(name)); -} - -function assertInvalidName(name) { - assertFalse(name + ' should be invalid', cookies.isValidName(name)); - assertThrows(function() { - cookies.set(name, 'value'); - }); -} - -function assertValidValue(val) { - assertTrue(val + ' should be valid', cookies.isValidValue(val)); -} - -function assertInvalidValue(val) { - assertFalse(val + ' should be invalid', cookies.isValidValue(val)); - assertThrows(function() { - cookies.set('name', val); - }); -} - -function testValidName() { - assertValidName('foo'); - assertInvalidName('foo bar'); - assertInvalidName('foo=bar'); - assertInvalidName('foo;bar'); - assertInvalidName('foo\nbar'); -} - -function testValidValue() { - assertValidValue('foo'); - assertValidValue('foo bar'); - assertValidValue('foo=bar'); - assertInvalidValue('foo;bar'); - assertInvalidValue('foo\nbar'); -} - -</script> -</body> -</html> diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/crossdomainrpc.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/crossdomainrpc.js.svn-base deleted file mode 100644 index 7952011..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/crossdomainrpc.js.svn-base +++ /dev/null @@ -1,849 +0,0 @@ -// Copyright 2006 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Cross domain RPC library using the <a - * href="http://go/xd2_design" target="_top">XD2 approach</a>. - * - * <h5>Protocol</h5> - * Client sends a request across domain via a form submission. Server - * receives these parameters: "xdpe:request-id", "xdpe:dummy-uri" ("xdpe" for - * "cross domain parameter to echo back") and other user parameters prefixed - * with "xdp" (for "cross domain parameter"). Headers are passed as parameters - * prefixed with "xdh" (for "cross domain header"). Only strings are supported - * for parameters and headers. A GET method is mapped to a form GET. All - * other methods are mapped to a POST. Server is expected to produce a - * HTML response such as the following: - * <pre> - * <body> - * <script type="text/javascript" - * src="path-to-crossdomainrpc.js"></script> - * var currentDirectory = location.href.substring( - * 0, location.href.lastIndexOf('/') - * ); - * - * // echo all parameters prefixed with "xdpe:" - * var echo = {}; - * echo[goog.net.CrossDomainRpc.PARAM_ECHO_REQUEST_ID] = - * <value of parameter "xdpe:request-id">; - * echo[goog.net.CrossDomainRpc.PARAM_ECHO_DUMMY_URI] = - * <value of parameter "xdpe:dummy-uri">; - * - * goog.net.CrossDomainRpc.sendResponse( - * '({"result":"<responseInJSON"})', - * true, // is JSON - * echo, // parameters to echo back - * status, // response status code - * headers // response headers - * ); - * </script> - * </body> - * </pre> - * - * <h5>Server Side</h5> - * For an example of the server side, refer to the following files: - * <ul> - * <li>http://go/xdservletfilter.java</li> - * <li>http://go/xdservletrequest.java</li> - * <li>http://go/xdservletresponse.java</li> - * </ul> - * - * <h5>System Requirements</h5> - * Tested on IE6, IE7, Firefox 2.0 and Safari nightly r23841. - * - */ - -goog.provide('goog.net.CrossDomainRpc'); - -goog.require('goog.Uri.QueryData'); -goog.require('goog.debug.Logger'); -goog.require('goog.dom'); -goog.require('goog.events'); -goog.require('goog.events.EventTarget'); -goog.require('goog.events.EventType'); -goog.require('goog.json'); -goog.require('goog.net.EventType'); -goog.require('goog.net.HttpStatus'); -goog.require('goog.userAgent'); - - - -/** - * Creates a new instance of cross domain RPC - * @extends {goog.events.EventTarget} - * @constructor - */ -goog.net.CrossDomainRpc = function() { - goog.events.EventTarget.call(this); -}; -goog.inherits(goog.net.CrossDomainRpc, goog.events.EventTarget); - - -/** - * Cross-domain response iframe marker. - * @type {string} - * @private - */ -goog.net.CrossDomainRpc.RESPONSE_MARKER_ = 'xdrp'; - - -/** - * Use a fallback dummy resource if none specified or detected. - * @type {boolean} - * @private - */ -goog.net.CrossDomainRpc.useFallBackDummyResource_ = true; - - -/** - * Checks to see if we are executing inside a response iframe. This is the - * case when this page is used as a dummy resource to gain caller's domain. - * @return {*} True if we are executing inside a response iframe; false - * otherwise. - * @private - */ -goog.net.CrossDomainRpc.isInResponseIframe_ = function() { - return window.location && (window.location.hash.indexOf( - goog.net.CrossDomainRpc.RESPONSE_MARKER_) == 1 || - window.location.search.indexOf( - goog.net.CrossDomainRpc.RESPONSE_MARKER_) == 1); -}; - - -/** - * Stops execution of the rest of the page if this page is loaded inside a - * response iframe. - */ -if (goog.net.CrossDomainRpc.isInResponseIframe_()) { - if (goog.userAgent.IE) { - document.execCommand('Stop'); - } else if (goog.userAgent.GECKO) { - window.stop(); - } else { - throw Error('stopped'); - } -} - - -/** - * Sets the URI for a dummy resource on caller's domain. This function is - * used for specifying a particular resource to use rather than relying on - * auto detection. - * @param {string} dummyResourceUri URI to dummy resource on the same domain - * of caller's page. - */ -goog.net.CrossDomainRpc.setDummyResourceUri = function(dummyResourceUri) { - goog.net.CrossDomainRpc.dummyResourceUri_ = dummyResourceUri; -}; - - -/** - * Sets whether a fallback dummy resource ("/robots.txt" on Firefox and Safari - * and current page on IE) should be used when a suitable dummy resource is - * not available. - * @param {boolean} useFallBack Whether to use fallback or not. - */ -goog.net.CrossDomainRpc.setUseFallBackDummyResource = function(useFallBack) { - goog.net.CrossDomainRpc.useFallBackDummyResource_ = useFallBack; -}; - - -/** - * Sends a request across domain. - * @param {string} uri Uri to make request to. - * @param {Function=} opt_continuation Continuation function to be called - * when request is completed. Takes one argument of an event object - * whose target has the following properties: "status" is the HTTP - * response status code, "responseText" is the response text, - * and "headers" is an object with all response headers. The event - * target's getResponseJson() method returns a JavaScript object evaluated - * from the JSON response or undefined if response is not JSON. - * @param {string=} opt_method Method of request. Default is POST. - * @param {Object=} opt_params Parameters. Each property is turned into a - * request parameter. - * @param {Object=} opt_headers Map of headers of the request. - */ -goog.net.CrossDomainRpc.send = - function(uri, opt_continuation, opt_method, opt_params, opt_headers) { - var xdrpc = new goog.net.CrossDomainRpc(); - if (opt_continuation) { - goog.events.listen(xdrpc, goog.net.EventType.COMPLETE, opt_continuation); - } - goog.events.listen(xdrpc, goog.net.EventType.READY, xdrpc.reset); - xdrpc.sendRequest(uri, opt_method, opt_params, opt_headers); -}; - - -/** - * Sets debug mode to true or false. When debug mode is on, response iframes - * are visible and left behind after their use is finished. - * @param {boolean} flag Flag to indicate intention to turn debug model on - * (true) or off (false). - */ -goog.net.CrossDomainRpc.setDebugMode = function(flag) { - goog.net.CrossDomainRpc.debugMode_ = flag; -}; - - -/** - * Logger for goog.net.CrossDomainRpc - * @type {goog.debug.Logger} - * @private - */ -goog.net.CrossDomainRpc.logger_ = - goog.debug.Logger.getLogger('goog.net.CrossDomainRpc'); - - -/** - * Creates the HTML of an input element - * @param {string} name Name of input element. - * @param {*} value Value of input element. - * @return {string} HTML of input element with that name and value. - * @private - */ -goog.net.CrossDomainRpc.createInputHtml_ = function(name, value) { - return '<textarea name="' + name + '">' + - goog.net.CrossDomainRpc.escapeAmpersand_(value) + '</textarea>'; -}; - - -/** - * Escapes ampersand so that XML/HTML entities are submitted as is because - * browser unescapes them when they are put into a text area. - * @param {*} value Value to escape. - * @return {*} Value with ampersand escaped, if value is a string; - * otherwise the value itself is returned. - * @private - */ -goog.net.CrossDomainRpc.escapeAmpersand_ = function(value) { - return value && (goog.isString(value) || value.constructor == String) ? - value.replace(/&/g, '&') : value; -}; - - -/** - * Finds a dummy resource that can be used by response to gain domain of - * requester's page. - * @return {string} URI of the resource to use. - * @private - */ -goog.net.CrossDomainRpc.getDummyResourceUri_ = function() { - if (goog.net.CrossDomainRpc.dummyResourceUri_) { - return goog.net.CrossDomainRpc.dummyResourceUri_; - } - - // find a style sheet if not on IE, which will attempt to save style sheet - if (goog.userAgent.GECKO) { - var links = document.getElementsByTagName('link'); - for (var i = 0; i < links.length; i++) { - var link = links[i]; - // find a link which is on the same domain as this page - // cannot use one with '?' or '#' in its URL as it will confuse - // goog.net.CrossDomainRpc.getFramePayload_() - if (link.rel == 'stylesheet' && - goog.Uri.haveSameDomain(link.href, window.location.href) && - link.href.indexOf('?') < 0) { - return goog.net.CrossDomainRpc.removeHash_(link.href); - } - } - } - - var images = document.getElementsByTagName('img'); - for (var i = 0; i < images.length; i++) { - var image = images[i]; - // find a link which is on the same domain as this page - // cannot use one with '?' or '#' in its URL as it will confuse - // goog.net.CrossDomainRpc.getFramePayload_() - if (goog.Uri.haveSameDomain(image.src, window.location.href) && - image.src.indexOf('?') < 0) { - return goog.net.CrossDomainRpc.removeHash_(image.src); - } - } - - if (!goog.net.CrossDomainRpc.useFallBackDummyResource_) { - throw Error( - 'No suitable dummy resource specified or detected for this page'); - } - - if (goog.userAgent.IE) { - // use this page as the dummy resource; remove hash from URL if any - return goog.net.CrossDomainRpc.removeHash_(window.location.href); - } else { - /** - * Try to use "http://<this-domain>/robots.txt" which may exist. Even if - * it does not, an error page is returned and is a good dummy resource to - * use on Firefox and Safari. An existing resource is faster because it - * is cached. - */ - var locationHref = window.location.href; - var rootSlash = locationHref.indexOf('/', locationHref.indexOf('//') + 2); - var rootHref = locationHref.substring(0, rootSlash); - return rootHref + '/robots.txt'; - } -}; - - -/** - * Removes everything at and after hash from URI - * @param {string} uri Uri to to remove hash. - * @return {string} Uri with its hash and all characters after removed. - * @private - */ -goog.net.CrossDomainRpc.removeHash_ = function(uri) { - return uri.split('#')[0]; -}; - - -// ------------ -// request side - - -/** - * next request id used to support multiple XD requests at the same time - * @type {number} - * @private - */ -goog.net.CrossDomainRpc.nextRequestId_ = 0; - - -/** - * Header prefix. - * @type {string} - */ -goog.net.CrossDomainRpc.HEADER = 'xdh:'; - - -/** - * Parameter prefix. - * @type {string} - */ -goog.net.CrossDomainRpc.PARAM = 'xdp:'; - - -/** - * Parameter to echo prefix. - * @type {string} - */ -goog.net.CrossDomainRpc.PARAM_ECHO = 'xdpe:'; - - -/** - * Parameter to echo: request id - * @type {string} - */ -goog.net.CrossDomainRpc.PARAM_ECHO_REQUEST_ID = - goog.net.CrossDomainRpc.PARAM_ECHO + 'request-id'; - - -/** - * Parameter to echo: dummy resource URI - * @type {string} - */ -goog.net.CrossDomainRpc.PARAM_ECHO_DUMMY_URI = - goog.net.CrossDomainRpc.PARAM_ECHO + 'dummy-uri'; - - -/** - * Cross-domain request marker. - * @type {string} - * @private - */ -goog.net.CrossDomainRpc.REQUEST_MARKER_ = 'xdrq'; - - -/** - * Sends a request across domain. - * @param {string} uri Uri to make request to. - * @param {string=} opt_method Method of request. Default is POST. - * @param {Object=} opt_params Parameters. Each property is turned into a - * request parameter. - * @param {Object=} opt_headers Map of headers of the request. - */ -goog.net.CrossDomainRpc.prototype.sendRequest = - function(uri, opt_method, opt_params, opt_headers) { - // create request frame - var requestFrame = this.requestFrame_ = document.createElement('iframe'); - var requestId = goog.net.CrossDomainRpc.nextRequestId_++; - requestFrame.id = goog.net.CrossDomainRpc.REQUEST_MARKER_ + '-' + requestId; - if (!goog.net.CrossDomainRpc.debugMode_) { - requestFrame.style.position = 'absolute'; - requestFrame.style.top = '-5000px'; - requestFrame.style.left = '-5000px'; - } - document.body.appendChild(requestFrame); - - // build inputs - var inputs = []; - - // add request id - inputs.push(goog.net.CrossDomainRpc.createInputHtml_( - goog.net.CrossDomainRpc.PARAM_ECHO_REQUEST_ID, requestId)); - - // add dummy resource uri - var dummyUri = goog.net.CrossDomainRpc.getDummyResourceUri_(); - goog.net.CrossDomainRpc.logger_.log( - goog.debug.Logger.Level.FINE, 'dummyUri: ' + dummyUri); - inputs.push(goog.net.CrossDomainRpc.createInputHtml_( - goog.net.CrossDomainRpc.PARAM_ECHO_DUMMY_URI, dummyUri)); - - // add parameters - if (opt_params) { - for (var name in opt_params) { - var value = opt_params[name]; - inputs.push(goog.net.CrossDomainRpc.createInputHtml_( - goog.net.CrossDomainRpc.PARAM + name, value)); - } - } - - // add headers - if (opt_headers) { - for (var name in opt_headers) { - var value = opt_headers[name]; - inputs.push(goog.net.CrossDomainRpc.createInputHtml_( - goog.net.CrossDomainRpc.HEADER + name, value)); - } - } - - var requestFrameContent = '<body><form method="' + - (opt_method == 'GET' ? 'GET' : 'POST') + '" action="' + - uri + '">' + inputs.join('') + '</form></body>'; - var requestFrameDoc = goog.dom.getFrameContentDocument(requestFrame); - requestFrameDoc.open(); - requestFrameDoc.write(requestFrameContent); - requestFrameDoc.close(); - - requestFrameDoc.forms[0].submit(); - requestFrameDoc = null; - - this.loadListenerKey_ = goog.events.listen( - requestFrame, goog.events.EventType.LOAD, function() { - goog.net.CrossDomainRpc.logger_.log(goog.debug.Logger.Level.FINE, - 'response ready'); - this.responseReady_ = true; - }, false, this); - - this.receiveResponse_(); -}; - - -/** - * period of response polling (ms) - * @type {number} - * @private - */ -goog.net.CrossDomainRpc.RESPONSE_POLLING_PERIOD_ = 50; - - -/** - * timeout from response comes back to sendResponse is called (ms) - * @type {number} - * @private - */ -goog.net.CrossDomainRpc.SEND_RESPONSE_TIME_OUT_ = 500; - - -/** - * Receives response by polling to check readiness of response and then - * reads response frames and assembles response data - * @private - */ -goog.net.CrossDomainRpc.prototype.receiveResponse_ = function() { - this.timeWaitedAfterResponseReady_ = 0; - var responseDetectorHandle = window.setInterval(goog.bind(function() { - this.detectResponse_(responseDetectorHandle); - }, this), goog.net.CrossDomainRpc.RESPONSE_POLLING_PERIOD_); -}; - - -/** - * Detects response inside request frame - * @param {number} responseDetectorHandle Handle of detector. - * @private - */ -goog.net.CrossDomainRpc.prototype.detectResponse_ = - function(responseDetectorHandle) { - var requestFrameWindow = this.requestFrame_.contentWindow; - var grandChildrenLength = requestFrameWindow.frames.length; - var responseInfoFrame = null; - if (grandChildrenLength > 0 && - goog.net.CrossDomainRpc.isResponseInfoFrame_(responseInfoFrame = - requestFrameWindow.frames[grandChildrenLength - 1])) { - goog.net.CrossDomainRpc.logger_.log(goog.debug.Logger.Level.FINE, - 'xd response ready'); - - var responseInfoPayload = goog.net.CrossDomainRpc.getFramePayload_( - responseInfoFrame).substring(1); - var params = new goog.Uri.QueryData(responseInfoPayload); - - var chunks = []; - var numChunks = Number(params.get('n')); - goog.net.CrossDomainRpc.logger_.log(goog.debug.Logger.Level.FINE, - 'xd response number of chunks: ' + numChunks); - for (var i = 0; i < numChunks; i++) { - var responseFrame = requestFrameWindow.frames[i]; - if (!responseFrame || !responseFrame.location || - !responseFrame.location.href) { - // On Safari 3.0, it is sometimes the case that the - // iframe exists but doesn't have a same domain href yet. - goog.net.CrossDomainRpc.logger_.log(goog.debug.Logger.Level.FINE, - 'xd response iframe not ready'); - return; - } - var responseChunkPayload = - goog.net.CrossDomainRpc.getFramePayload_(responseFrame); - // go past "chunk=" - var chunkIndex = responseChunkPayload.indexOf( - goog.net.CrossDomainRpc.PARAM_CHUNK_) + - goog.net.CrossDomainRpc.PARAM_CHUNK_.length + 1; - var chunk = responseChunkPayload.substring(chunkIndex); - chunks.push(chunk); - } - - window.clearInterval(responseDetectorHandle); - - var responseData = chunks.join(''); - // Payload is not encoded to begin with on IE. Decode in other cases only. - if (!goog.userAgent.IE) { - responseData = decodeURIComponent(responseData); - } - - this.status = Number(params.get('status')); - this.responseText = responseData; - this.responseTextIsJson_ = params.get('isDataJson') == 'true'; - this.responseHeaders = goog.json.unsafeParse( - /** @type {string} */ (params.get('headers'))); - - this.dispatchEvent(goog.net.EventType.READY); - this.dispatchEvent(goog.net.EventType.COMPLETE); - } else { - if (this.responseReady_) { - /* The response has come back. But the first response iframe has not - * been created yet. If this lasts long enough, it is an error. - */ - this.timeWaitedAfterResponseReady_ += - goog.net.CrossDomainRpc.RESPONSE_POLLING_PERIOD_; - if (this.timeWaitedAfterResponseReady_ > - goog.net.CrossDomainRpc.SEND_RESPONSE_TIME_OUT_) { - goog.net.CrossDomainRpc.logger_.log(goog.debug.Logger.Level.FINE, - 'xd response timed out'); - window.clearInterval(responseDetectorHandle); - - this.status = goog.net.HttpStatus.INTERNAL_SERVER_ERROR; - this.responseText = 'response timed out'; - - this.dispatchEvent(goog.net.EventType.READY); - this.dispatchEvent(goog.net.EventType.ERROR); - this.dispatchEvent(goog.net.EventType.COMPLETE); - } - } - } -}; - - -/** - * Checks whether a frame is response info frame. - * @param {Object} frame Frame to check. - * @return {boolean} True if frame is a response info frame; false otherwise. - * @private - */ -goog.net.CrossDomainRpc.isResponseInfoFrame_ = function(frame) { - /** @preserveTry */ - try { - return goog.net.CrossDomainRpc.getFramePayload_(frame).indexOf( - goog.net.CrossDomainRpc.RESPONSE_INFO_MARKER_) == 1; - } catch (e) { - // frame not ready for same-domain access yet - return false; - } -}; - - -/** - * Returns the payload of a frame (value after # or ? on the URL). This value - * is URL encoded except IE, where the value is not encoded to begin with. - * @param {Object} frame Frame. - * @return {string} Payload of that frame. - * @private - */ -goog.net.CrossDomainRpc.getFramePayload_ = function(frame) { - var href = frame.location.href; - var question = href.indexOf('?'); - var hash = href.indexOf('#'); - // On IE, beucase the URL is not encoded, we can have a case where ? - // is the delimiter before payload and # in payload or # as the delimiter - // and ? in payload. So here we treat whoever is the first as the delimiter. - var delimiter = question < 0 ? hash : - hash < 0 ? question : Math.min(question, hash); - return href.substring(delimiter); -}; - - -/** - * If response is JSON, evaluates it to a JavaScript object and - * returns it; otherwise returns undefined. - * @return {Object|undefined} JavaScript object if response is in JSON - * or undefined. - */ -goog.net.CrossDomainRpc.prototype.getResponseJson = function() { - return this.responseTextIsJson_ ? - goog.json.unsafeParse(this.responseText) : undefined; -}; - - -/** - * @return {boolean} Whether the request completed with a success. - */ -goog.net.CrossDomainRpc.prototype.isSuccess = function() { - // Definition similar to goog.net.XhrIo.prototype.isSuccess. - switch (this.status) { - case goog.net.HttpStatus.OK: - case goog.net.HttpStatus.NOT_MODIFIED: - return true; - - default: - return false; - } -}; - - -/** - * Removes request iframe used. - */ -goog.net.CrossDomainRpc.prototype.reset = function() { - if (!goog.net.CrossDomainRpc.debugMode_) { - goog.net.CrossDomainRpc.logger_.log(goog.debug.Logger.Level.FINE, - 'request frame removed: ' + this.requestFrame_.id); - goog.events.unlistenByKey(this.loadListenerKey_); - this.requestFrame_.parentNode.removeChild(this.requestFrame_); - } - delete this.requestFrame_; -}; - - -// ------------- -// response side - - -/** - * Name of response info iframe. - * @type {string} - * @private - */ -goog.net.CrossDomainRpc.RESPONSE_INFO_MARKER_ = - goog.net.CrossDomainRpc.RESPONSE_MARKER_ + '-info'; - - -/** - * Maximal chunk size. IE can only handle 4095 bytes on its URL. - * 16MB has been tested on Firefox. But 1MB is a practical size. - * @type {number} - * @private - */ -goog.net.CrossDomainRpc.MAX_CHUNK_SIZE_ = - goog.userAgent.IE ? 4095 : 1024 * 1024; - - -/** - * Query parameter 'chunk'. - * @type {string} - * @private - */ -goog.net.CrossDomainRpc.PARAM_CHUNK_ = 'chunk'; - - -/** - * Prefix before data chunk for passing other parameters. - * type String - * @private - */ -goog.net.CrossDomainRpc.CHUNK_PREFIX_ = - goog.net.CrossDomainRpc.RESPONSE_MARKER_ + '=1&' + - goog.net.CrossDomainRpc.PARAM_CHUNK_ + '='; - - -/** - * Makes response available for grandparent (requester)'s receiveResponse - * call to pick up by creating a series of iframes pointed to the dummy URI - * with a payload (value after either ? or #) carrying a chunk of response - * data and a response info iframe that tells the grandparent (requester) the - * readiness of response. - * @param {string} data Response data (string or JSON string). - * @param {boolean} isDataJson true if data is a JSON string; false if just a - * string. - * @param {Object} echo Parameters to echo back - * "xdpe:request-id": Server that produces the response needs to - * copy it here to support multiple current XD requests on the same page. - * "xdpe:dummy-uri": URI to a dummy resource that response - * iframes point to to gain the domain of the client. This can be an - * image (IE) or a CSS file (FF) found on the requester's page. - * Server should copy value from request parameter "xdpe:dummy-uri". - * @param {number} status HTTP response status code. - * @param {string} headers Response headers in JSON format. - */ -goog.net.CrossDomainRpc.sendResponse = - function(data, isDataJson, echo, status, headers) { - var dummyUri = echo[goog.net.CrossDomainRpc.PARAM_ECHO_DUMMY_URI]; - - // since the dummy-uri can be specified by the user, verify that it doesn't - // use any other protocols. (Specifically we don't want users to use a - // dummy-uri beginning with "javascript:"). - if (!goog.string.caseInsensitiveStartsWith(dummyUri, 'http://') && - !goog.string.caseInsensitiveStartsWith(dummyUri, 'https://')) { - dummyUri = 'http://' + dummyUri; - } - - // usable chunk size is max less dummy URI less chunk prefix length - // TODO(user): Figure out why we need to do "- 1" below - var chunkSize = goog.net.CrossDomainRpc.MAX_CHUNK_SIZE_ - dummyUri.length - - 1 - // payload delimiter ('#' or '?') - goog.net.CrossDomainRpc.CHUNK_PREFIX_.length - 1; - - /* - * Here we used to do URI encoding of data before we divide it into chunks - * and decode on the receiving end. We don't do this any more on IE for the - * following reasons. - * - * 1) On IE, calling decodeURIComponent on a relatively large string is - * extremely slow (~22s for 160KB). So even a moderate amount of data - * makes this library pretty much useless. Fortunately, we can actually - * put unencoded data on IE's URL and get it back reliably. So we are - * completely skipping encoding and decoding on IE. When we call - * getFrameHash_ to get it back, the value is still intact(*) and unencoded. - * 2) On Firefox, we have to call decodeURIComponent because location.hash - * does decoding by itself. Fortunately, decodeURIComponent is not slow - * on Firefox. - * 3) Safari automatically encodes everything you put on URL and it does not - * automatically decode when you access it via location.hash or - * location.href. So we encode it here and decode it in detectResponse_(). - * - * Note(*): IE actually does encode only space to %20 and decodes that - * automatically when you do location.href or location.hash. - */ - if (!goog.userAgent.IE) { - data = encodeURIComponent(data); - } - - var numChunksToSend = Math.ceil(data.length / chunkSize); - if (numChunksToSend == 0) { - goog.net.CrossDomainRpc.createResponseInfo_( - dummyUri, numChunksToSend, isDataJson, status, headers); - } else { - var numChunksSent = 0; - function checkToCreateResponseInfo_() { - if (++numChunksSent == numChunksToSend) { - goog.net.CrossDomainRpc.createResponseInfo_( - dummyUri, numChunksToSend, isDataJson, status, headers); - } - } - - for (var i = 0; i < numChunksToSend; i++) { - var chunkStart = i * chunkSize; - var chunkEnd = chunkStart + chunkSize; - var chunk = chunkEnd > data.length ? - data.substring(chunkStart) : - data.substring(chunkStart, chunkEnd); - - var responseFrame = document.createElement('iframe'); - responseFrame.src = dummyUri + - goog.net.CrossDomainRpc.getPayloadDelimiter_(dummyUri) + - goog.net.CrossDomainRpc.CHUNK_PREFIX_ + chunk; - document.body.appendChild(responseFrame); - - // We used to call the function below when handling load event of - // responseFrame. But that event does not fire on IE when current - // page is used as the dummy resource (because its loading is stopped?). - // It also does not fire sometimes on Firefox. So now we call it - // directly. - checkToCreateResponseInfo_(); - } - } -}; - - -/** - * Creates a response info iframe to indicate completion of sendResponse - * @param {string} dummyUri URI to a dummy resource. - * @param {number} numChunks Total number of chunks. - * @param {boolean} isDataJson Whether response is a JSON string or just string. - * @param {number} status HTTP response status code. - * @param {string} headers Response headers in JSON format. - * @private - */ -goog.net.CrossDomainRpc.createResponseInfo_ = - function(dummyUri, numChunks, isDataJson, status, headers) { - var responseInfoFrame = document.createElement('iframe'); - document.body.appendChild(responseInfoFrame); - responseInfoFrame.src = dummyUri + - goog.net.CrossDomainRpc.getPayloadDelimiter_(dummyUri) + - goog.net.CrossDomainRpc.RESPONSE_INFO_MARKER_ + - '=1&n=' + numChunks + '&isDataJson=' + isDataJson + '&status=' + status + - '&headers=' + encodeURIComponent(headers); -}; - - -/** - * Returns payload delimiter, either "#" when caller's page is not used as - * the dummy resource or "?" when it is, in which case caching issues prevent - * response frames to gain the caller's domain. - * @param {string} dummyUri URI to resource being used as dummy resource. - * @return {string} Either "?" when caller's page is used as dummy resource or - * "#" if it is not. - * @private - */ -goog.net.CrossDomainRpc.getPayloadDelimiter_ = function(dummyUri) { - return goog.net.CrossDomainRpc.REFERRER_ == dummyUri ? '?' : '#'; -}; - - -/** - * Removes all parameters (after ? or #) from URI. - * @param {string} uri URI to remove parameters from. - * @return {string} URI with all parameters removed. - * @private - */ -goog.net.CrossDomainRpc.removeUriParams_ = function(uri) { - // remove everything after question mark - var question = uri.indexOf('?'); - if (question > 0) { - uri = uri.substring(0, question); - } - - // remove everything after hash mark - var hash = uri.indexOf('#'); - if (hash > 0) { - uri = uri.substring(0, hash); - } - - return uri; -}; - - -/** - * Gets a response header. - * @param {string} name Name of response header. - * @return {string|undefined} Value of response header; undefined if not found. - */ -goog.net.CrossDomainRpc.prototype.getResponseHeader = function(name) { - return goog.isObject(this.responseHeaders) ? - this.responseHeaders[name] : undefined; -}; - - -/** - * Referrer of current document with all parameters after "?" and "#" stripped. - * @type {string} - * @private - */ -goog.net.CrossDomainRpc.REFERRER_ = - goog.net.CrossDomainRpc.removeUriParams_(document.referrer); diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/crossdomainrpc_test.gif.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/crossdomainrpc_test.gif.svn-base deleted file mode 100644 index e69de29..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/crossdomainrpc_test.gif.svn-base +++ /dev/null diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/crossdomainrpc_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/crossdomainrpc_test.html.svn-base deleted file mode 100644 index fbb077f..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/crossdomainrpc_test.html.svn-base +++ /dev/null @@ -1,120 +0,0 @@ -<!DOCTYPE html> -<html> -<!-- -Copyright 2007 The Closure Library Authors. All Rights Reserved. - -Use of this source code is governed by the Apache License, Version 2.0. -See the COPYING file for details. ---> -<!-- ---> -<head> -<meta http-equiv="X-UA-Compatible" content="IE=edge"> -<title>Closure Unit Tests - goog.net.CrossDomainRpc</title> -<link href="CrossDomainRpc_test.css?123" rel="stylesheet" type="text/css"> -<link href="CrossDomainRpc_test.css#123" rel="stylesheet" type="text/css"> -<link href="CrossDomainRpc_test.css" rel="stylesheet" type="text/css"> -<script src="../base.js"></script> -<script> - goog.require('goog.debug.Logger'); - goog.require('goog.net.CrossDomainRpc'); - goog.require('goog.testing.jsunit'); -</script> - -<script> - -// TODO(user): These tests are in fact async since the send command makes a -// request for a file, the reason they do not fail is that the JsUnit test -// runner reports completion after the testFoo functions are finished, and -// does not catch any errors after this point. These tests need updating so -// that they either mock out the async part of the test, or they should be -// written as an async test case. - -function print(o) { - if (Object.prototype.toSource) { - return o.toSource(); - } else { - var fragments = []; - fragments.push('{'); - var first = true; - for (var p in o) { - if (!first) fragments.push(','); - fragments.push(p); - fragments.push(':"'); - fragments.push(o[p]); - fragments.push('"'); - first = false; - } - return fragments.join(''); - } -}; - - -function testNormalRequest() { - var start = new Date(); - goog.net.CrossDomainRpc.send( - 'crossdomainrpc_test_response.html', - function(e) { - if (e.target.status < 300) { - var elapsed = new Date() - start; - var responseData = eval(e.target.responseText); - goog.net.CrossDomainRpc.logger_.log(goog.debug.Logger.Level.FINE, - elapsed + 'ms: [' + responseData.result.length + '] ' - + print(responseData) - ); - assertEquals(16 * 1024, responseData.result.length); - assertEquals(e.target.status, 123); - assertEquals(e.target.responseHeaders.a, 1); - assertEquals(e.target.responseHeaders.b, '2'); - } else { - goog.net.CrossDomainRpc.logger_.log(goog.debug.Logger.Level.FINE, - print(e)); - fail(); - } - }, - 'POST', - {xyz: '01234567891123456789'} - ); -}; - - -function testErrorRequest() { - goog.net.CrossDomainRpc.send( - 'http://hoodjimcwaadji.google.com/index.html', - function(e) { - if (e.target.status < 300) { - fail('should have failed requesting a non-existent URI'); - } else { - goog.net.CrossDomainRpc.logger_.log(goog.debug.Logger.Level.FINE, - 'expected error seen; event=' + print(e)); - } - }, - 'POST', - {xyz: '01234567891123456789'} - ); -}; - - -function testGetDummyResourceUri() { - var url = goog.net.CrossDomainRpc.getDummyResourceUri_(); - assertTrue( - 'dummy resource URL should not contain "?"', url.indexOf('?') < 0); - assertTrue( - 'dummy resource URL should not contain "#"', url.indexOf('#') < 0); -}; - - -function testRemoveHash() { - assertEquals('abc', goog.net.CrossDomainRpc.removeHash_('abc#123')); - assertEquals('abc', goog.net.CrossDomainRpc.removeHash_('abc#12#3')); -}; -</script> -</head> - -<body> -<img src="crossdomainrpc_test.gif?123" alt="dummy resource"> -<img src="crossdomainrpc_test.gif#123" alt="dummy resource"> -<img src="crossdomainrpc_test.gif" alt="dummy resource"> -</body> - -</html> diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/crossdomainrpc_test_response.html.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/crossdomainrpc_test_response.html.svn-base deleted file mode 100644 index b44a01b..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/crossdomainrpc_test_response.html.svn-base +++ /dev/null @@ -1,59 +0,0 @@ -<!DOCTYPE html> -<html> -<!-- -Copyright 2007 The Closure Library Authors. All Rights Reserved. - -Use of this source code is governed by the Apache License, Version 2.0. -See the COPYING file for details. ---> -<!-- - - - In reality, this response comes from a different domain. For simplicity of - testing, this response is one the same domain, while exercising the same - functionality. ---> -<title>crossdomainrpc test response</title> -<body> -<script type="text/javascript" src="../base.js"></script> -<script type="text/javascript"> -goog.require('goog.debug.Logger'); -goog.require('goog.dom'); -goog.require('goog.events.EventTarget'); -goog.require('goog.json'); -goog.require('goog.net.EventType'); -goog.require('goog.Uri.QueryData'); -goog.require('goog.userAgent'); -</script> -<script type="text/javascript" src="crossdomainrpc.js"></script> -<script type="text/javascript"> -function createPayload(size) { - var chars = []; - for (var i = 0; i < size; i++) { - chars.push('0'); - } - return chars.join(''); -}; - -var payload = createPayload(16 * 1024); - -var currentDirectory = location.href.substring( - 0, location.href.lastIndexOf('/') -); - -var echo = {}; -echo[goog.net.CrossDomainRpc.PARAM_ECHO_REQUEST_ID] = 0; -echo[goog.net.CrossDomainRpc.PARAM_ECHO_DUMMY_URI] = goog.userAgent.IE ? - currentDirectory + '/crossdomainrpc_test.gif' : - currentDirectory + '/crossdomainrpc_test.css'; - -goog.net.CrossDomainRpc.sendResponse( - '({"result":"' + payload + '"})', - true, // is JSON - echo, // parameters to echo back - 123, // response code - '{"a":1,"b":"2"}' // response headers -); -</script> -</body> -</html> diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/errorcode.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/errorcode.js.svn-base deleted file mode 100644 index 4d6d834..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/errorcode.js.svn-base +++ /dev/null @@ -1,130 +0,0 @@ -// Copyright 2007 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Error codes shared between goog.net.IframeIo and - * goog.net.XhrIo. - */ - -goog.provide('goog.net.ErrorCode'); - - -/** - * Error codes - * @enum {number} - */ -goog.net.ErrorCode = { - - /** - * There is no error condition. - */ - NO_ERROR: 0, - - /** - * The most common error from iframeio, unfortunately, is that the browser - * responded with an error page that is classed as a different domain. The - * situations, are when a browser error page is shown -- 404, access denied, - * DNS failure, connection reset etc.) - * - */ - ACCESS_DENIED: 1, - - /** - * Currently the only case where file not found will be caused is when the - * code is running on the local file system and a non-IE browser makes a - * request to a file that doesn't exist. - */ - FILE_NOT_FOUND: 2, - - /** - * If Firefox shows a browser error page, such as a connection reset by - * server or access denied, then it will fail silently without the error or - * load handlers firing. - */ - FF_SILENT_ERROR: 3, - - /** - * Custom error provided by the client through the error check hook. - */ - CUSTOM_ERROR: 4, - - /** - * Exception was thrown while processing the request. - */ - EXCEPTION: 5, - - /** - * The Http response returned a non-successful http status code. - */ - HTTP_ERROR: 6, - - /** - * The request was aborted. - */ - ABORT: 7, - - /** - * The request timed out. - */ - TIMEOUT: 8, - - /** - * The resource is not available offline. - */ - OFFLINE: 9 -}; - - -/** - * Returns a friendly error message for an error code. These messages are for - * debugging and are not localized. - * @param {goog.net.ErrorCode} errorCode An error code. - * @return {string} A message for debugging. - */ -goog.net.ErrorCode.getDebugMessage = function(errorCode) { - switch (errorCode) { - case goog.net.ErrorCode.NO_ERROR: - return 'No Error'; - - case goog.net.ErrorCode.ACCESS_DENIED: - return 'Access denied to content document'; - - case goog.net.ErrorCode.FILE_NOT_FOUND: - return 'File not found'; - - case goog.net.ErrorCode.FF_SILENT_ERROR: - return 'Firefox silently errored'; - - case goog.net.ErrorCode.CUSTOM_ERROR: - return 'Application custom error'; - - case goog.net.ErrorCode.EXCEPTION: - return 'An exception occurred'; - - case goog.net.ErrorCode.HTTP_ERROR: - return 'Http response at 400 or 500 level'; - - case goog.net.ErrorCode.ABORT: - return 'Request was aborted'; - - case goog.net.ErrorCode.TIMEOUT: - return 'Request timed out'; - - case goog.net.ErrorCode.OFFLINE: - return 'The resource is not available offline'; - - default: - return 'Unrecognized error code'; - } -}; diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/eventtype.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/eventtype.js.svn-base deleted file mode 100644 index ac86979..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/eventtype.js.svn-base +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2006 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Common events for the network classes. - */ - - -goog.provide('goog.net.EventType'); - - -/** - * Event names for network events - * @enum {string} - */ -goog.net.EventType = { - COMPLETE: 'complete', - SUCCESS: 'success', - ERROR: 'error', - ABORT: 'abort', - READY: 'ready', - READY_STATE_CHANGE: 'readystatechange', - TIMEOUT: 'timeout', - INCREMENTAL_DATA: 'incrementaldata', - PROGRESS: 'progress' -}; diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/filedownloader.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/filedownloader.js.svn-base deleted file mode 100644 index da551a1..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/filedownloader.js.svn-base +++ /dev/null @@ -1,741 +0,0 @@ -// Copyright 2011 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview A class for downloading remote files and storing them - * locally using the HTML5 FileSystem API. - * - * The directory structure is of the form /HASH/URL/BASENAME: - * - * The HASH portion is a three-character slice of the hash of the URL. Since the - * filesystem has a limit of about 5000 files per directory, this should divide - * the downloads roughly evenly among about 5000 directories, thus allowing for - * at most 5000^2 downloads. - * - * The URL portion is the (sanitized) full URL used for downloading the file. - * This is used to ensure that each file ends up in a different location, even - * if the HASH and BASENAME are the same. - * - * The BASENAME portion is the basename of the URL. It's used for the filename - * proper so that the local filesystem: URL will be downloaded to a file with a - * recognizable name. - * - */ - -goog.provide('goog.net.FileDownloader'); -goog.provide('goog.net.FileDownloader.Error'); - -goog.require('goog.Disposable'); -goog.require('goog.asserts'); -goog.require('goog.async.Deferred'); -goog.require('goog.crypt.hash32'); -goog.require('goog.debug.Error'); -goog.require('goog.events.EventHandler'); -goog.require('goog.fs'); -goog.require('goog.fs.DirectoryEntry.Behavior'); -goog.require('goog.fs.Error.ErrorCode'); -goog.require('goog.fs.FileSaver.EventType'); -goog.require('goog.net.EventType'); -goog.require('goog.net.XhrIo.ResponseType'); -goog.require('goog.net.XhrIoPool'); - - - -/** - * A class for downloading remote files and storing them locally using the - * HTML5 filesystem API. - * - * @param {!goog.fs.DirectoryEntry} dir The directory in which the downloaded - * files are stored. This directory should be solely managed by - * FileDownloader. - * @param {goog.net.XhrIoPool=} opt_pool The pool of XhrIo objects to use for - * downloading files. - * @constructor - * @extends {goog.Disposable} - */ -goog.net.FileDownloader = function(dir, opt_pool) { - goog.base(this); - - /** - * The directory in which the downloaded files are stored. - * @type {!goog.fs.DirectoryEntry} - * @private - */ - this.dir_ = dir; - - /** - * The pool of XHRs to use for capturing. - * @type {!goog.net.XhrIoPool} - * @private - */ - this.pool_ = opt_pool || new goog.net.XhrIoPool(); - - /** - * A map from URLs to active downloads running for those URLs. - * @type {!Object.<!goog.net.FileDownloader.Download_>} - * @private - */ - this.downloads_ = {}; - - /** - * The handler for URL capturing events. - * @type {!goog.events.EventHandler} - * @private - */ - this.eventHandler_ = new goog.events.EventHandler(this); -}; -goog.inherits(goog.net.FileDownloader, goog.Disposable); - - -/** - * Download a remote file and save its contents to the filesystem. A given file - * is uniquely identified by its URL string; this means that the relative and - * absolute URLs for a single file are considered different for the purposes of - * the FileDownloader. - * - * Returns a Deferred that will contain the downloaded blob. If there's an error - * while downloading the URL, this Deferred will be passed the - * {@link goog.net.FileDownloader.Error} object as an errback. - * - * If a download is already in progress for the given URL, this will return the - * deferred blob for that download. If the URL has already been downloaded, this - * will fail once it tries to save the downloaded blob. - * - * When a download is in progress, all Deferreds returned for that download will - * be branches of a single parent. If all such branches are cancelled, or if one - * is cancelled with opt_deepCancel set, then the download will be cancelled as - * well. - * - * @param {string} url The URL of the file to download. - * @return {!goog.async.Deferred} The deferred result blob. - */ -goog.net.FileDownloader.prototype.download = function(url) { - if (this.isDownloading(url)) { - return this.downloads_[url].deferred.branch(true /* opt_propagateCancel */); - } - - var download = new goog.net.FileDownloader.Download_(url, this); - this.downloads_[url] = download; - this.pool_.getObject(goog.bind(this.gotXhr_, this, download)); - return download.deferred.branch(true /* opt_propagateCancel */); -}; - - -/** - * Return a Deferred that will fire once no download is active for a given URL. - * If there's no download active for that URL when this is called, the deferred - * will fire immediately; otherwise, it will fire once the download is complete, - * whether or not it succeeds. - * - * @param {string} url The URL of the download to wait for. - * @return {!goog.async.Deferred} The Deferred that will fire when the download - * is complete. - */ -goog.net.FileDownloader.prototype.waitForDownload = function(url) { - var deferred = new goog.async.Deferred(); - if (this.isDownloading(url)) { - this.downloads_[url].deferred.addBoth(function() { - deferred.callback(null); - }, this); - } else { - deferred.callback(null); - } - return deferred; -}; - - -/** - * Returns whether or not there is an active download for a given URL. - * - * @param {string} url The URL of the download to check. - * @return {boolean} Whether or not there is an active download for the URL. - */ -goog.net.FileDownloader.prototype.isDownloading = function(url) { - return url in this.downloads_; -}; - - -/** - * Load a downloaded blob from the filesystem. Will fire a deferred error if the - * given URL has not yet been downloaded. - * - * @param {string} url The URL of the blob to load. - * @return {!goog.async.Deferred} The deferred Blob object. The callback will be - * passed the blob. If a file API error occurs while loading the blob, that - * error will be passed to the errback. - */ -goog.net.FileDownloader.prototype.getDownloadedBlob = function(url) { - return this.getFile_(url). - addCallback(function(fileEntry) { return fileEntry.file(); }); -}; - - -/** - * Get the local filesystem: URL for a downloaded file. This is different from - * the blob: URL that's available from getDownloadedBlob(). If the end user - * accesses the filesystem: URL, the resulting file's name will be determined by - * the download filename as opposed to an arbitrary GUID. In addition, the - * filesystem: URL is connected to a filesystem location, so if the download is - * removed then that URL will become invalid. - * - * Warning: in Chrome 12, some filesystem: URLs are opened inline. This means - * that e.g. HTML pages given to the user via filesystem: URLs will be opened - * and processed by the browser. - * - * @param {string} url The URL of the file to get the URL of. - * @return {!goog.async.Deferred} The deferred filesystem: URL. The callback - * will be passed the URL. If a file API error occurs while loading the - * blob, that error will be passed to the errback. - */ -goog.net.FileDownloader.prototype.getLocalUrl = function(url) { - return this.getFile_(url). - addCallback(function(fileEntry) { return fileEntry.toUrl(); }); -}; - - -/** - * Return (deferred) whether or not a URL has been downloaded. Will fire a - * deferred error if something goes wrong when determining this. - * - * @param {string} url The URL to check. - * @return {!goog.async.Deferred} The deferred boolean. The callback will be - * passed the boolean. If a file API error occurs while checking the - * existence of the downloaded URL, that error will be passed to the - * errback. - */ -goog.net.FileDownloader.prototype.isDownloaded = function(url) { - var deferred = new goog.async.Deferred(); - var blobDeferred = this.getDownloadedBlob(url); - blobDeferred.addCallback(function() { - deferred.callback(true); - }); - blobDeferred.addErrback(function(err) { - if (err.code == goog.fs.Error.ErrorCode.NOT_FOUND) { - deferred.callback(false); - } else { - deferred.errback(err); - } - }); - return deferred; -}; - - -/** - * Remove a URL from the FileDownloader. - * - * This returns a Deferred. If the removal is completed successfully, its - * callback will be called without any value. If the removal fails, its errback - * will be called with the {@link goog.fs.Error}. - * - * @param {string} url The URL to remove. - * @return {!goog.async.Deferred} The deferred used for registering callbacks on - * success or on error. - */ -goog.net.FileDownloader.prototype.remove = function(url) { - return this.getDir_(url, goog.fs.DirectoryEntry.Behavior.DEFAULT). - addCallback(function(dir) { return dir.removeRecursively(); }); -}; - - -/** - * Save a blob for a given URL. This works just as through the blob were - * downloaded form that URL, except you specify the blob and no HTTP request is - * made. - * - * If the URL is currently being downloaded, it's indeterminate whether the blob - * being set or the blob being downloaded will end up in the filesystem. - * Whichever one doesn't get saved will have an error. To ensure that one or the - * other takes precedence, use {@link #waitForDownload} to allow the download to - * complete before setting the blob. - * - * @param {string} url The URL at which to set the blob. - * @param {!Blob} blob The blob to set. - * @param {string=} opt_name The name of the file. If this isn't given, it's - * determined from the URL. - * @return {!goog.async.Deferred} The deferred used for registering callbacks on - * success or on error. This can be cancelled just like a {@link #download} - * Deferred. The objects passed to the errback will be - * {@link goog.net.FileDownloader.Error}s. - */ -goog.net.FileDownloader.prototype.setBlob = function(url, blob, opt_name) { - var name = this.sanitize_(opt_name || this.urlToName_(url)); - var download = new goog.net.FileDownloader.Download_(url, this); - this.downloads_[url] = download; - download.blob = blob; - this.getDir_(download.url, goog.fs.DirectoryEntry.Behavior.CREATE_EXCLUSIVE). - addCallback(function(dir) { - return dir.getFile( - name, goog.fs.DirectoryEntry.Behavior.CREATE_EXCLUSIVE); - }). - addCallback(goog.bind(this.fileSuccess_, this, download)). - addErrback(goog.bind(this.error_, this, download)); - return download.deferred.branch(true /* opt_propagateCancel */); -}; - - -/** - * The callback called when an XHR becomes available from the XHR pool. - * - * @param {!goog.net.FileDownloader.Download_} download The download object for - * this download. - * @param {!goog.net.XhrIo} xhr The XhrIo object for downloading the page. - * @private - */ -goog.net.FileDownloader.prototype.gotXhr_ = function(download, xhr) { - if (download.cancelled) { - this.freeXhr_(xhr); - return; - } - - this.eventHandler_.listen( - xhr, goog.net.EventType.SUCCESS, - goog.bind(this.xhrSuccess_, this, download)); - this.eventHandler_.listen( - xhr, [goog.net.EventType.ERROR, goog.net.EventType.ABORT], - goog.bind(this.error_, this, download)); - this.eventHandler_.listen( - xhr, goog.net.EventType.READY, - goog.bind(this.freeXhr_, this, xhr)); - - download.xhr = xhr; - xhr.setResponseType(goog.net.XhrIo.ResponseType.ARRAY_BUFFER); - xhr.send(download.url); -}; - - -/** - * The callback called when an XHR succeeds in downloading a remote file. - * - * @param {!goog.net.FileDownloader.Download_} download The download object for - * this download. - * @private - */ -goog.net.FileDownloader.prototype.xhrSuccess_ = function(download) { - if (download.cancelled) { - return; - } - - var name = this.sanitize_(this.getName_( - /** @type {!goog.net.XhrIo} */ (download.xhr))); - var resp = /** @type {ArrayBuffer} */ (download.xhr.getResponse()); - if (!resp) { - // This should never happen - it indicates the XHR hasn't completed, has - // failed or has been cleaned up. If it does happen (eg. due to a bug - // somewhere) we don't want to pass null to getBlob - it's not valid and - // triggers a bug in some versions of WebKit causing it to crash. - this.error_(download); - return; - } - - download.blob = goog.fs.getBlob(resp); - delete download.xhr; - - this.getDir_(download.url, goog.fs.DirectoryEntry.Behavior.CREATE_EXCLUSIVE). - addCallback(function(dir) { - return dir.getFile( - name, goog.fs.DirectoryEntry.Behavior.CREATE_EXCLUSIVE); - }). - addCallback(goog.bind(this.fileSuccess_, this, download)). - addErrback(goog.bind(this.error_, this, download)); -}; - - -/** - * The callback called when a file that will be used for saving a file is - * successfully opened. - * - * @param {!goog.net.FileDownloader.Download_} download The download object for - * this download. - * @param {!goog.fs.FileEntry} file The newly-opened file object. - * @private - */ -goog.net.FileDownloader.prototype.fileSuccess_ = function(download, file) { - if (download.cancelled) { - file.remove(); - return; - } - - download.file = file; - file.createWriter(). - addCallback(goog.bind(this.fileWriterSuccess_, this, download)). - addErrback(goog.bind(this.error_, this, download)); -}; - - -/** - * The callback called when a file writer is succesfully created for writing a - * file to the filesystem. - * - * @param {!goog.net.FileDownloader.Download_} download The download object for - * this download. - * @param {!goog.fs.FileWriter} writer The newly-created file writer object. - * @private - */ -goog.net.FileDownloader.prototype.fileWriterSuccess_ = function( - download, writer) { - if (download.cancelled) { - download.file.remove(); - return; - } - - download.writer = writer; - writer.write(/** @type {!Blob} */ (download.blob)); - this.eventHandler_.listenOnce( - writer, - goog.fs.FileSaver.EventType.WRITE_END, - goog.bind(this.writeEnd_, this, download)); -}; - - -/** - * The callback called when file writing ends, whether or not it's successful. - * - * @param {!goog.net.FileDownloader.Download_} download The download object for - * this download. - * @private - */ -goog.net.FileDownloader.prototype.writeEnd_ = function(download) { - if (download.cancelled || download.writer.getError()) { - this.error_(download, download.writer.getError()); - return; - } - - delete this.downloads_[download.url]; - download.deferred.callback(download.blob); -}; - - -/** - * The error callback for all asynchronous operations. Ensures that all stages - * of a given download are cleaned up, and emits the error event. - * - * @param {!goog.net.FileDownloader.Download_} download The download object for - * this download. - * @param {goog.fs.Error=} opt_err The file error object. Only defined if the - * error was raised by the file API. - * @private - */ -goog.net.FileDownloader.prototype.error_ = function(download, opt_err) { - if (download.file) { - download.file.remove(); - } - - if (download.cancelled) { - return; - } - - delete this.downloads_[download.url]; - download.deferred.errback( - new goog.net.FileDownloader.Error(download, opt_err)); -}; - - -/** - * Abort the download of the given URL. - * - * @param {!goog.net.FileDownloader.Download_} download The download to abort. - * @private - */ -goog.net.FileDownloader.prototype.cancel_ = function(download) { - goog.dispose(download); - delete this.downloads_[download.url]; -}; - - -/** - * Get the directory for a given URL. If the directory already exists when this - * is called, it will contain exactly one file: the downloaded file. - * - * This not only calls the FileSystem API's getFile method, but attempts to - * distribute the files so that they don't overload the filesystem. The spec - * says directories can't contain more than 5000 files - * (http://www.w3.org/TR/file-system-api/#directories), so this ensures that - * each file is put into a subdirectory based on its SHA1 hash. - * - * All parameters are the same as in the FileSystem API's Entry#getFile method. - * - * @param {string} url The URL corresponding to the directory to get. - * @param {goog.fs.DirectoryEntry.Behavior} behavior The behavior to pass to the - * underlying method. - * @return {!goog.async.Deferred} The deferred DirectoryEntry object. - * @private - */ -goog.net.FileDownloader.prototype.getDir_ = function(url, behavior) { - // 3 hex digits provide 16**3 = 4096 different possible dirnames, which is - // less than the maximum of 5000 entries. Downloaded files should be - // distributed roughly evenly throughout the directories due to the hash - // function, allowing many more than 5000 files to be downloaded. - // - // The leading ` ensures that no illegal dirnames are accidentally used. % was - // previously used, but Chrome has a bug (as of 12.0.725.0 dev) where - // filenames are URL-decoded before checking their validity, so filenames - // containing e.g. '%3f' (the URL-encoding of :, an invalid character) are - // rejected. - var dirname = '`' + Math.abs(goog.crypt.hash32.encodeString(url)). - toString(16).substring(0, 3); - - return this.dir_. - getDirectory(dirname, goog.fs.DirectoryEntry.Behavior.CREATE). - addCallback(function(dir) { - return dir.getDirectory(this.sanitize_(url), behavior); - }, this); -}; - - -/** - * Get the file for a given URL. This will only retrieve files that have already - * been saved; it shouldn't be used for creating the file in the first place. - * This is because the filename isn't necessarily determined by the URL, but by - * the headers of the XHR response. - * - * @param {string} url The URL corresponding to the file to get. - * @return {!goog.async.Deferred} The deferred FileEntry object. - * @private - */ -goog.net.FileDownloader.prototype.getFile_ = function(url) { - return this.getDir_(url, goog.fs.DirectoryEntry.Behavior.DEFAULT). - addCallback(function(dir) { - return dir.listDirectory().addCallback(function(files) { - goog.asserts.assert(files.length == 1); - // If the filesystem somehow gets corrupted and we end up with an - // empty directory here, it makes sense to just return the normal - // file-not-found error. - return files[0] || dir.getFile('file'); - }); - }); -}; - - -/** - * Sanitize a string so it can be safely used as a file or directory name for - * the FileSystem API. - * - * @param {string} str The string to sanitize. - * @return {string} The sanitized string. - * @private - */ -goog.net.FileDownloader.prototype.sanitize_ = function(str) { - // Add a prefix, since certain prefixes are disallowed for paths. None of the - // disallowed prefixes start with '`'. We use ` rather than % for escaping the - // filename due to a Chrome bug (as of 12.0.725.0 dev) where filenames are - // URL-decoded before checking their validity, so filenames containing e.g. - // '%3f' (the URL-encoding of :, an invalid character) are rejected. - return '`' + str.replace(/[\/\\<>:?*"|%`]/g, encodeURIComponent). - replace(/%/g, '`'); -}; - - -/** - * Gets the filename specified by the XHR. This first attempts to parse the - * Content-Disposition header for a filename and, failing that, falls back on - * deriving the filename from the URL. - * - * @param {!goog.net.XhrIo} xhr The XHR containing the response headers. - * @return {string} The filename. - * @private - */ -goog.net.FileDownloader.prototype.getName_ = function(xhr) { - var disposition = xhr.getResponseHeader('Content-Disposition'); - var match = disposition && - disposition.match(/^attachment *; *filename="(.*)"$/i); - if (match) { - // The Content-Disposition header allows for arbitrary backslash-escaped - // characters (usually " and \). We want to unescape them before using them - // in the filename. - return match[1].replace(/\\(.)/g, '$1'); - } - - return this.urlToName_(xhr.getLastUri()); -}; - - -/** - * Extracts the basename from a URL. - * - * @param {string} url The URL. - * @return {string} The basename. - * @private - */ -goog.net.FileDownloader.prototype.urlToName_ = function(url) { - var segments = url.split('/'); - return segments[segments.length - 1]; -}; - - -/** - * Remove all event listeners for an XHR and release it back into the pool. - * - * @param {!goog.net.XhrIo} xhr The XHR to free. - * @private - */ -goog.net.FileDownloader.prototype.freeXhr_ = function(xhr) { - goog.events.removeAll(xhr); - this.pool_.addFreeObject(xhr); -}; - - -/** @override */ -goog.net.FileDownloader.prototype.disposeInternal = function() { - delete this.dir_; - goog.dispose(this.eventHandler_); - delete this.eventHandler_; - goog.object.forEach(this.downloads_, function(download) { - download.deferred.cancel(); - }, this); - delete this.downloads_; - goog.dispose(this.pool_); - delete this.pool_; - - goog.base(this, 'disposeInternal'); -}; - - - -/** - * The error object for FileDownloader download errors. - * - * @param {!goog.net.FileDownloader.Download_} download The download object for - * the download in question. - * @param {goog.fs.Error=} opt_fsErr The file error object, if this was a file - * error. - * - * @constructor - * @extends {goog.debug.Error} - */ -goog.net.FileDownloader.Error = function(download, opt_fsErr) { - goog.base(this, 'Error capturing URL ' + download.url); - - /** - * The URL the event relates to. - * @type {string} - */ - this.url = download.url; - - if (download.xhr) { - this.xhrStatus = download.xhr.getStatus(); - this.xhrErrorCode = download.xhr.getLastErrorCode(); - this.message += ': XHR failed with status ' + this.xhrStatus + - ' (error code ' + this.xhrErrorCode + ')'; - } else if (opt_fsErr) { - this.fileError = opt_fsErr; - this.message += ': file API failed (' + opt_fsErr.message + ')'; - } -}; -goog.inherits(goog.net.FileDownloader.Error, goog.debug.Error); - - -/** - * The status of the XHR. Only set if the error was caused by an XHR failure. - * @type {number|undefined} - */ -goog.net.FileDownloader.Error.prototype.xhrStatus; - - -/** - * The error code of the XHR. Only set if the error was caused by an XHR - * failure. - * @type {goog.net.ErrorCode|undefined} - */ -goog.net.FileDownloader.Error.prototype.xhrErrorCode; - - -/** - * The file API error. Only set if the error was caused by the file API. - * @type {goog.fs.Error|undefined} - */ -goog.net.FileDownloader.Error.prototype.fileError; - - - -/** - * A struct containing the data for a single download. - * - * @param {string} url The URL for the file being downloaded. - * @param {!goog.net.FileDownloader} downloader The parent FileDownloader. - * @extends {goog.Disposable} - * @constructor - * @private - */ -goog.net.FileDownloader.Download_ = function(url, downloader) { - goog.base(this); - - /** - * The URL for the file being downloaded. - * @type {string} - */ - this.url = url; - - /** - * The Deferred that will be fired when the download is complete. - * @type {!goog.async.Deferred} - */ - this.deferred = new goog.async.Deferred( - goog.bind(downloader.cancel_, downloader, this)); - - /** - * Whether this download has been cancelled by the user. - * @type {boolean} - */ - this.cancelled = false; - - /** - * The XhrIo object for downloading the file. Only set once it's been - * retrieved from the pool. - * @type {goog.net.XhrIo} - */ - this.xhr = null; - - /** - * The name of the blob being downloaded. Only sey once the XHR has completed, - * if it completed successfully. - * @type {?string} - */ - this.name = null; - - /** - * The downloaded blob. Only set once the XHR has completed, if it completed - * successfully. - * @type {Blob} - */ - this.blob = null; - - /** - * The file entry where the blob is to be stored. Only set once it's been - * loaded from the filesystem. - * @type {goog.fs.FileEntry} - */ - this.file = null; - - /** - * The file writer for writing the blob to the filesystem. Only set once it's - * been loaded from the filesystem. - * @type {goog.fs.FileWriter} - */ - this.writer = null; -}; -goog.inherits(goog.net.FileDownloader.Download_, goog.Disposable); - - -/** @override */ -goog.net.FileDownloader.Download_.prototype.disposeInternal = function() { - this.cancelled = true; - if (this.xhr) { - this.xhr.abort(); - } else if (this.writer && this.writer.getReadyState() == - goog.fs.FileSaver.ReadyState.WRITING) { - this.writer.abort(); - } - - goog.base(this, 'disposeInternal'); -}; diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/filedownloader_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/filedownloader_test.html.svn-base deleted file mode 100644 index f70b54a..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/filedownloader_test.html.svn-base +++ /dev/null @@ -1,372 +0,0 @@ -<!DOCTYPE html> -<html> -<!-- -Copyright 2011 The Closure Library Authors. All Rights Reserved. - -Use of this source code is governed by the Apache License, Version 2.0. -See the COPYING file for details. ---> -<!-- ---> -<head> -<title>Closure Unit Tests - goog.net.FileDownloader</title> -<script src="../base.js"></script> -<script> -goog.require('goog.fs.Error.ErrorCode') -goog.require('goog.net.ErrorCode') -goog.require('goog.net.FileDownloader') -goog.require('goog.testing.fs') -goog.require('goog.testing.jsunit') -goog.require('goog.testing.net.XhrIoPool') -goog.require('goog.testing.AsyncTestCase') -goog.require('goog.testing.PropertyReplacer') -</script> -</head> -<body> -<script> - -var asyncTestCase = goog.testing.AsyncTestCase.createAndInstall(); -var xhrIoPool, xhr, fs, dir, downloader; - -function setUpPage() { - goog.testing.fs.install(new goog.testing.PropertyReplacer()); -} - -function setUp() { - xhrIoPool = new goog.testing.net.XhrIoPool(); - xhr = xhrIoPool.getXhr(); - fs = new goog.testing.fs.FileSystem(); - dir = fs.getRoot(); - downloader = new goog.net.FileDownloader(dir, xhrIoPool); -} - -function tearDown() { - goog.dispose(downloader); -} - -function testDownload() { - downloader.download('/foo/bar').addCallback(function(blob) { - var fileEntry = dir.getFileSync('`3fa/``2Ffoo`2Fbar/`bar'); - assertEquals('data', blob.toString()); - assertEquals('data', fileEntry.fileSync().toString()); - asyncTestCase.continueTesting(); - }).addErrback(function(err) { throw err; }); - - assertEquals('/foo/bar', xhr.getLastUri()); - assertEquals(goog.net.XhrIo.ResponseType.ARRAY_BUFFER, xhr.getResponseType()); - - xhr.simulateResponse(200, 'data'); - asyncTestCase.waitForAsync('testDownload'); -} - -function testGetDownloadedBlob() { - downloader.download('/foo/bar'). - addCallback(function() { - return downloader.getDownloadedBlob('/foo/bar'); - }). - addCallback(function(blob) { assertEquals('data', blob.toString()); }). - addCallback(goog.bind(asyncTestCase.continueTesting, asyncTestCase)). - addErrback(function(err) { throw err; }); - - xhr.simulateResponse(200, 'data'); - asyncTestCase.waitForAsync('testGetDownloadedBlob'); -} - -function testGetLocalUrl() { - downloader.download('/foo/bar'). - addCallback(function() { return downloader.getLocalUrl('/foo/bar'); }). - addCallback(function(url) { assertMatches(/\/`bar$/, url); }). - addCallback(goog.bind(asyncTestCase.continueTesting, asyncTestCase)). - addErrback(function(err) { throw err; }); - - xhr.simulateResponse(200, 'data'); - asyncTestCase.waitForAsync('testGetLocalUrl'); -} - -function testLocalUrlWithContentDisposition() { - downloader.download('/foo/bar'). - addCallback(function() { return downloader.getLocalUrl('/foo/bar'); }). - addCallback(function(url) { assertMatches(/\/`qux`22bap$/, url); }). - addCallback(goog.bind(asyncTestCase.continueTesting, asyncTestCase)). - addErrback(function(err) { throw err; }); - - xhr.simulateResponse( - 200, 'data', {'Content-Disposition': 'attachment; filename="qux\\"bap"'}); - asyncTestCase.waitForAsync('testGetLocalUrl'); -} - -function testIsDownloaded() { - downloader.download('/foo/bar'). - addCallback(function() { return downloader.isDownloaded('/foo/bar'); }). - addCallback(assertTrue). - addCallback(function() { return downloader.isDownloaded('/foo/baz'); }). - addCallback(assertFalse). - addCallback(goog.bind(asyncTestCase.continueTesting, asyncTestCase)). - addErrback(function(err) { throw err; }); - - xhr.simulateResponse(200, 'data'); - asyncTestCase.waitForAsync('testIsDownloaded'); -} - -function testRemove() { - downloader.download('/foo/bar'). - addCallback(function() { return downloader.remove('/foo/bar'); }). - addCallback(function() { return downloader.isDownloaded('/foo/bar'); }). - addCallback(assertFalse). - addCallback(function() { - return downloader.getDownloadedBlob('/foo/bar'); - }). - addErrback(function(err) { - assertEquals(goog.fs.Error.ErrorCode.NOT_FOUND, err.code); - var download = downloader.download('/foo/bar'); - xhr.simulateResponse(200, 'more data'); - return download; - }). - addCallback(function() { return downloader.isDownloaded('/foo/bar'); }). - addCallback(assertTrue). - addCallback(function() { - return downloader.getDownloadedBlob('/foo/bar'); - }). - addCallback(function(blob) { - assertEquals('more data', blob.toString()); - }). - addCallback(goog.bind(asyncTestCase.continueTesting, asyncTestCase)); - - xhr.simulateResponse(200, 'data'); - asyncTestCase.waitForAsync('testRemove'); -} - -function testSetBlob() { - downloader.setBlob('/foo/bar', goog.testing.fs.getBlob('data')). - addCallback(function() { return downloader.isDownloaded('/foo/bar'); }). - addCallback(assertTrue). - addCallback(function() { - return downloader.getDownloadedBlob('/foo/bar'); - }). - addCallback(function(blob) { - assertEquals('data', blob.toString()); - }). - addCallback(goog.bind(asyncTestCase.continueTesting, asyncTestCase)). - addErrback(function(err) { throw err; }); - - asyncTestCase.waitForAsync('testSetBlob'); -} - -function testSetBlobWithName() { - downloader.setBlob('/foo/bar', goog.testing.fs.getBlob('data'), 'qux'). - addCallback(function() { return downloader.getLocalUrl('/foo/bar'); }). - addCallback(function(url) { assertMatches(/\/`qux$/, url); }). - addCallback(goog.bind(asyncTestCase.continueTesting, asyncTestCase)). - addErrback(function(err) { throw err; }); - - asyncTestCase.waitForAsync('testSetBlob'); -} - -function testDownloadDuringDownload() { - var download1 = downloader.download('/foo/bar'); - var download2 = downloader.download('/foo/bar'); - - download1. - addCallback(function() { return download2; }). - addCallback(function() { - return downloader.getDownloadedBlob('/foo/bar'); - }). - addCallback(function(blob) { assertEquals('data', blob.toString()); }). - addCallback(goog.bind(asyncTestCase.continueTesting, asyncTestCase)); - - // There should only need to be one response for both downloads, since the - // second should return the same deferred as the first. - xhr.simulateResponse(200, 'data'); - asyncTestCase.waitForAsync('testDownloadeduringDownload'); -} - -function testGetDownloadedBlobDuringDownload() { - var download = downloader.download('/foo/bar'); - downloader.waitForDownload('/foo/bar').addCallback(function() { - return downloader.getDownloadedBlob('/foo/bar'); - }).addCallback(function(blob) { - assertTrue(download.hasFired()); - assertEquals('data', blob.toString()); - asyncTestCase.continueTesting(); - }); - - xhr.simulateResponse(200, 'data'); - asyncTestCase.waitForAsync('testGetDownloadedBlobDuringDownload'); -} - -function testIsDownloadedDuringDownload() { - var download = downloader.download('/foo/bar'); - downloader.waitForDownload('/foo/bar').addCallback(function() { - return downloader.isDownloaded('/foo/bar'); - }).addCallback(function(isDownloaded) { - assertTrue(download.hasFired()); - assertTrue(isDownloaded); - asyncTestCase.continueTesting(); - }); - - xhr.simulateResponse(200, 'data'); - asyncTestCase.waitForAsync('testIsDownloadedDuringDownload'); -} - -function testRemoveDuringDownload() { - var download = downloader.download('/foo/bar'); - downloader. - waitForDownload('/foo/bar'). - addCallback(function() { return downloader.remove('/foo/bar'); }). - addCallback(function() { assertTrue(download.hasFired()); }). - addCallback(function() { return downloader.isDownloaded('/foo/bar'); }). - addCallback(assertFalse). - addCallback(goog.bind(asyncTestCase.continueTesting, asyncTestCase)); - - xhr.simulateResponse(200, 'data'); - asyncTestCase.waitForAsync('testRemoveDuringDownload'); -} - -function testSetBlobDuringDownload() { - var download = downloader.download('/foo/bar'); - downloader. - waitForDownload('/foo/bar'). - addCallback(function() { - return downloader.setBlob( - '/foo/bar', goog.testing.fs.getBlob('blob data')); - }). - addErrback(function(err) { - assertEquals(goog.fs.Error.ErrorCode.PATH_EXISTS, err.fileError.code); - return download; - }). - addCallback(function() { - return downloader.getDownloadedBlob('/foo/bar'); - }). - addCallback(function(b) { assertEquals('xhr data', b.toString()); }). - addCallback(goog.bind(asyncTestCase.continueTesting, asyncTestCase)); - - xhr.simulateResponse(200, 'xhr data'); - asyncTestCase.waitForAsync('testSetBlobDuringDownload'); -} - -function testDownloadCancelledBeforeXhr() { - var download = downloader.download('/foo/bar'); - download.cancel(); - - download. - addErrback(function() { - assertEquals('/foo/bar', xhr.getLastUri()); - assertEquals(goog.net.ErrorCode.ABORT, xhr.getLastErrorCode()); - assertFalse(xhr.isActive()); - - return downloader.isDownloaded('/foo/bar'); - }). - addCallback(assertFalse). - addCallback(goog.bind(asyncTestCase.continueTesting, asyncTestCase)); - - asyncTestCase.waitForAsync('testDownloadCancelledBeforeXhr'); -} - -function testDownloadCancelledAfterXhr() { - var download = downloader.download('/foo/bar'); - xhr.simulateResponse(200, 'data'); - download.cancel(); - - download. - addErrback(function() { - assertEquals('/foo/bar', xhr.getLastUri()); - assertEquals(goog.net.ErrorCode.NO_ERROR, xhr.getLastErrorCode()); - assertFalse(xhr.isActive()); - - return downloader.isDownloaded('/foo/bar'); - }). - addCallback(assertFalse). - addCallback(goog.bind(asyncTestCase.continueTesting, asyncTestCase)); - - asyncTestCase.waitForAsync('testDownloadCancelledAfterXhr'); -} - -function testFailedXhr() { - downloader.download('/foo/bar'). - addErrback(function(err) { - assertEquals('/foo/bar', err.url); - assertEquals(404, err.xhrStatus); - assertEquals(goog.net.ErrorCode.HTTP_ERROR, err.xhrErrorCode); - assertUndefined(err.fileError); - - return downloader.isDownloaded('/foo/bar'); - }). - addCallback(assertFalse). - addCallback(goog.bind(asyncTestCase.continueTesting, asyncTestCase)); - - xhr.simulateResponse(404); - asyncTestCase.waitForAsync('testFailedXhr'); -} - -function testFailedDownloadSave() { - downloader.download('/foo/bar'). - addCallback(function() { - var download = downloader.download('/foo/bar'); - xhr.simulateResponse(200, 'data'); - return download; - }). - addErrback(function(err) { - assertEquals('/foo/bar', err.url); - assertUndefined(err.xhrStatus); - assertUndefined(err.xhrErrorCode); - assertEquals(goog.fs.Error.ErrorCode.PATH_EXISTS, err.fileError.code); - - asyncTestCase.continueTesting(); - }); - - xhr.simulateResponse(200, 'data'); - asyncTestCase.waitForAsync('testFailedDownloadSave'); -} - -function testFailedGetDownloadedBlob() { - downloader.getDownloadedBlob('/foo/bar'). - addErrback(function(err) { - assertEquals(goog.fs.Error.ErrorCode.NOT_FOUND, err.code); - asyncTestCase.continueTesting(); - }); - - asyncTestCase.waitForAsync('testFailedGetDownloadedBlob'); -} - -function testFailedRemove() { - downloader.remove('/foo/bar'). - addErrback(function(err) { - assertEquals(goog.fs.Error.ErrorCode.NOT_FOUND, err.code); - asyncTestCase.continueTesting(); - }); - - asyncTestCase.waitForAsync('testFailedRemove'); -} - -function testIsDownloading() { - assertFalse(downloader.isDownloading('/foo/bar')); - downloader.download('/foo/bar').addCallback(function() { - assertFalse(downloader.isDownloading('/foo/bar')); - asyncTestCase.continueTesting(); - }); - - assertTrue(downloader.isDownloading('/foo/bar')); - - xhr.simulateResponse(200, 'data'); - asyncTestCase.waitForAsync('testIsDownloading'); -} - -function testIsDownloadingWhenCancelled() { - assertFalse(downloader.isDownloading('/foo/bar')); - var deferred = downloader.download('/foo/bar').addErrback(function() { - assertFalse(downloader.isDownloading('/foo/bar')); - }); - - assertTrue(downloader.isDownloading('/foo/bar')); - deferred.cancel(); -} - -function assertMatches(expected, actual) { - assert( - 'Expected "' + actual + '" to match ' + expected, - expected.test(actual)); -} - -</script> -</body> -</html> diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/httpstatus.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/httpstatus.js.svn-base deleted file mode 100644 index eecb270..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/httpstatus.js.svn-base +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright 2011 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Constants for HTTP status codes. - */ - -goog.provide('goog.net.HttpStatus'); - - -/** - * HTTP Status Codes defined in RFC 2616. - * @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html - * @enum {number} - */ -goog.net.HttpStatus = { - // Informational 1xx - CONTINUE: 100, - SWITCHING_PROTOCOLS: 101, - - // Successful 2xx - OK: 200, - CREATED: 201, - ACCEPTED: 202, - NON_AUTHORITATIVE_INFORMATION: 203, - NO_CONTENT: 204, - RESET_CONTENT: 205, - PARTIAL_CONTENT: 206, - - // Redirection 3xx - MULTIPLE_CHOICES: 300, - MOVED_PERMANENTLY: 301, - FOUND: 302, - SEE_OTHER: 303, - NOT_MODIFIED: 304, - USE_PROXY: 305, - TEMPORARY_REDIRECT: 307, - - // Client Error 4xx - BAD_REQUEST: 400, - UNAUTHORIZED: 401, - PAYMENT_REQUIRED: 402, - FORBIDDEN: 403, - NOT_FOUND: 404, - METHOD_NOT_ALLOWED: 405, - NOT_ACCEPTABLE: 406, - PROXY_AUTHENTICATION_REQUIRED: 407, - REQUEST_TIMEOUT: 408, - CONFLICT: 409, - GONE: 410, - LENGTH_REQUIRED: 411, - PRECONDITION_FAILED: 412, - REQUEST_ENTITY_TOO_LARGE: 413, - REQUEST_URI_TOO_LONG: 414, - UNSUPPORTED_MEDIA_TYPE: 415, - REQUEST_RANGE_NOT_SATISFIABLE: 416, - EXPECTATION_FAILED: 417, - - // Server Error 5xx - INTERNAL_SERVER_ERROR: 500, - NOT_IMPLEMENTED: 501, - BAD_GATEWAY: 502, - SERVICE_UNAVAILABLE: 503, - GATEWAY_TIMEOUT: 504, - HTTP_VERSION_NOT_SUPPORTED: 505, - - /* - * IE returns this code for 204 due to its use of URLMon, which returns this - * code for 'Operation Aborted'. The status text is 'Unknown', the response - * headers are ''. Known to occur on IE 6 on XP through IE9 on Win7. - */ - QUIRK_IE_NO_CONTENT: 1223 -}; - - -/** - * Returns whether the given status should be considered successful. - * - * Successful codes are OK (200), CREATED (201), ACCEPTED (202), - * NO CONTENT (204), NOT MODIFIED (304), and IE's no content code (1223). - * - * @param {number} status The status code to test. - * @return {boolean} Whether the status code should be considered successful. - */ -goog.net.HttpStatus.isSuccess = function(status) { - switch (status) { - case goog.net.HttpStatus.OK: - case goog.net.HttpStatus.CREATED: - case goog.net.HttpStatus.ACCEPTED: - case goog.net.HttpStatus.NO_CONTENT: - case goog.net.HttpStatus.NOT_MODIFIED: - case goog.net.HttpStatus.QUIRK_IE_NO_CONTENT: - return true; - - default: - return false; - } -}; diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/iframe_xhr_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/iframe_xhr_test.html.svn-base deleted file mode 100644 index d2f4a14..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/iframe_xhr_test.html.svn-base +++ /dev/null @@ -1,147 +0,0 @@ -<!DOCTYPE html> -<html> -<!-- -Copyright 2007 The Closure Library Authors. All Rights Reserved. - -Use of this source code is governed by the Apache License, Version 2.0. -See the COPYING file for details. ---> -<head> -<meta http-equiv="X-UA-Compatible" content="IE=edge"> -<title>Closure Unit Tests - Iframe/XHR Execution Context</title> -<script src="../base.js"></script> -<script> - goog.require('goog.events'); - goog.require('goog.debug.Console'); - goog.require('goog.net.XhrLite'); - goog.require('goog.net.IframeIo'); - goog.require('goog.testing.AsyncTestCase'); - goog.require('goog.testing.jsunit'); - goog.require('goog.Timer'); -</script> -</head> -<body> - <p> - XmlHttpRequests that initiate from code executed in an iframe, that is then - destroyed, result in an error in FireFox. This test case is used to verify - that Closure's IframeIo and XhrLite do not suffer from this problem. See - <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=369939"> - https://bugzilla.mozilla.org/show_bug.cgi?id=369939</a>. - </p> - <p> - NOTE(pupius): 14/11/2011 The XhrMonitor code has been removed since the - above bug doesn't manifest in any currently supported versions. This test - is left in place as a way of verifying the problem doesn't resurface. - </p> - <script> - var c = new goog.debug.Console; - c.setCapturing(true); - goog.debug.LogManager.getRoot().setLevel(goog.debug.Logger.Level.ALL); - - // Can't use exportSymbol if we want JsUnit support - top.GG_iframeFn = goog.net.IframeIo.handleIncrementalData; - - // Make the dispose time short enough that it will cause the bug to appear - goog.net.IframeIo.IFRAME_DISPOSE_DELAY_MS = 0; - - - var fileName = 'iframe_xhr_test_response.html'; - var iframeio; - - // Create an async test case - var testCase = new goog.testing.AsyncTestCase(document.title); - testCase.stepTimeout = 4 * 1000; - testCase.resultCount = 0; - testCase.xhrCount = 0; - testCase.error = null; - - /** Set up the iframe io and request the test response page. */ - testCase.setUpPage = function() { - testCase.waitForAsync('setUpPage'); - iframeio = new goog.net.IframeIo(); - goog.events.listen( - iframeio, 'incrementaldata', this.onIframeData, false, this); - goog.events.listen( - iframeio, 'ready', this.onIframeReady, false, this); - iframeio.send(fileName); - - this.add(new goog.testing.TestCase.Test( - 'test results', this.testResults, this)); - }; - - /** Disposes the iframe object. */ - testCase.tearDownPage = function() { - iframeio.dispose(); - }; - - /** Handles the packets received from the Iframe incremental results. */ - testCase.onIframeData = function(e) { - this.log('Data received : ' + e.data); - this.resultCount++; - goog.net.XhrLite.send(fileName, goog.bind(this.onXhrData, this)); - }; - - /** Handles the iframe becoming ready. */ - testCase.onIframeReady = function(e) { - this.log('Iframe ready'); - var me = this; - goog.net.XhrLite.send(fileName, goog.bind(this.onXhrData, this)); - }; - - /** Handles the response from an Xhr request. */ - testCase.onXhrData = function(e) { - this.xhrCount++; - // We access status directly so that XhrLite doesn't mask the error that - // would be thrown in FF if this worked correctly. - try { - this.log('Xhr Received: ' + e.target.xhr_.status); - } catch (e) { - this.log('ERROR: ' + e.message); - this.error = e; - } - if (this.xhrCount == 4 && this.resultCount == 3) { - // Wait for the async iframe disposal to fire. - this.log('Test set up finished, waiting 500ms for iframe disposal'); - goog.Timer.callOnce(goog.bind(this.continueTesting, this), 0); - } - }; - - /** The main test function that validates the results were as expected. */ - testCase.testResults = function() { - assertEquals('There should be 3 data packets', 3, this.resultCount); - // 3 results + 1 ready - assertEquals('There should be 4 XHR results', 4, this.xhrCount); - if (this.error) { - throw this.error; - } - - assertEquals('There should be no iframes left', 0, - document.getElementsByTagName('iframe').length); - } - - /** This test only runs on GECKO browsers. */ - if (goog.userAgent.GECKO) { - /** Used by the JsUnit test runner. */ - var testXhrMonitorWorksForIframeIoRequests = function() { - testCase.reset(); - testCase.cycleTests(); - } - - /** Used by the JsUnit test runner. */ - var setUpPage = function() { - testCase.runTests(); - } - } - - // Standalone Closure Test Runner. - if (typeof G_testRunner != 'undefined') { - if (goog.userAgent.GECKO) { - G_testRunner.initialize(testCase); - } else { - G_testRunner.setStrict(false); - } - } - - </script> -</body> -</html> diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/iframe_xhr_test_response.html.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/iframe_xhr_test_response.html.svn-base deleted file mode 100644 index 3dafbef..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/iframe_xhr_test_response.html.svn-base +++ /dev/null @@ -1,17 +0,0 @@ -<html> -<!-- -Copyright 2010 The Closure Library Authors. All Rights Reserved. - -Use of this source code is governed by the Apache License, Version 2.0. -See the COPYING file for details. ---> - <head> -<meta http-equiv="X-UA-Compatible" content="IE=edge"> - <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"> - </head> - <body> - <script>top.GG_iframeFn(window, [1, 1, 2, 4, 8]);</script> - <script>top.GG_iframeFn(window, [12, 20, 32, 52, 84]);</script> - <script>top.GG_iframeFn(window, [136, 220, 356, 576, 932]);</script> - </body> -</html> diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/iframeio.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/iframeio.js.svn-base deleted file mode 100644 index deb8b39..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/iframeio.js.svn-base +++ /dev/null @@ -1,1300 +0,0 @@ -// Copyright 2006 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Class for managing requests via iFrames. Supports a number of - * methods of transfer. - * - * Gets and Posts can be performed and the resultant page read in as text, - * JSON, or from the HTML DOM. - * - * Using an iframe causes the throbber to spin, this is good for providing - * feedback to the user that an action has occurred. - * - * Requests do not affect the history stack, see goog.History if you require - * this behavior. - * - * The responseText and responseJson methods assume the response is plain, - * text. You can access the Iframe's DOM through responseXml if you need - * access to the raw HTML. - * - * Tested: - * + FF2.0 (Win Linux) - * + IE6, IE7 - * + Opera 9.1, - * + Chrome - * - Opera 8.5 fails because of no textContent and buggy innerText support - * - * NOTE: Safari doesn't fire the onload handler when loading plain text files - * - * This has been tested with Drip in IE to ensure memory usage is as constant - * as possible. When making making thousands of requests, memory usage stays - * constant for a while but then starts increasing (<500k for 2000 - * requests) -- this hasn't yet been tracked down yet, though it is cleared up - * after a refresh. - * - * - * BACKGROUND FILE UPLOAD: - * By posting an arbitrary form through an IframeIo object, it is possible to - * implement background file uploads. Here's how to do it: - * - * - Create a form: - * <pre> - * <form id="form" enctype="multipart/form-data" method="POST"> - * <input name="userfile" type="file" /> - * </form> - * </pre> - * - * - Have the user click the file input - * - Create an IframeIo instance - * <pre> - * var io = new goog.net.IframeIo; - * goog.events.listen(io, goog.net.EventType.COMPLETE, - * function() { alert('Sent'); }); - * io.sendFromForm(document.getElementById('form')); - * </pre> - * - * - * INCREMENTAL LOADING: - * Gmail sends down multiple script blocks which get executed as they are - * received by the client. This allows incremental rendering of the thread - * list and conversations. - * - * This requires collaboration with the server that is sending the requested - * page back. To set incremental loading up, you should: - * - * A) In the application code there should be an externed reference to - * <code>handleIncrementalData()</code>. e.g. - * goog.exportSymbol('GG_iframeFn', goog.net.IframeIo.handleIncrementalData); - * - * B) The response page should them call this method directly, an example - * response would look something like this: - * <pre> - * <html> - * <head> - * <meta content="text/html;charset=UTF-8" http-equiv="content-type"> - * </head> - * <body> - * <script> - * D = top.P ? function(d) { top.GG_iframeFn(window, d) } : function() {}; - * </script> - * - * <script>D([1, 2, 3, 4, 5]);</script> - * <script>D([6, 7, 8, 9, 10]);</script> - * <script>D([11, 12, 13, 14, 15]);</script> - * </body> - * </html> - * </pre> - * - * Your application should then listen, on the IframeIo instance, to the event - * goog.net.EventType.INCREMENTAL_DATA. The event object contains a - * 'data' member which is the content from the D() calls above. - * - * NOTE: There can be problems if you save a reference to the data object in IE. - * If you save an array, and the iframe is dispose, then the array looses its - * prototype and thus array methods like .join(). You can get around this by - * creating arrays using the parent window's Array constructor, or you can - * clone the array. - * - * - * EVENT MODEL: - * The various send methods work asynchronously. You can be notified about - * the current status of the request (completed, success or error) by - * listening for events on the IframeIo object itself. The following events - * will be sent: - * - goog.net.EventType.COMPLETE: when the request is completed - * (either sucessfully or unsuccessfully). You can find out about the result - * using the isSuccess() and getLastError - * methods. - * - goog.net.EventType.SUCCESS</code>: when the request was completed - * successfully - * - goog.net.EventType.ERROR: when the request failed - * - goog.net.EventType.ABORT: when the request has been aborted - * - * Example: - * <pre> - * var io = new goog.net.IframeIo(); - * goog.events.listen(io, goog.net.EventType.COMPLETE, - * function() { alert('request complete'); }); - * io.sendFromForm(...); - * </pre> - * - */ - -goog.provide('goog.net.IframeIo'); -goog.provide('goog.net.IframeIo.IncrementalDataEvent'); - -goog.require('goog.Timer'); -goog.require('goog.Uri'); -goog.require('goog.debug'); -goog.require('goog.debug.Logger'); -goog.require('goog.dom'); -goog.require('goog.events'); -goog.require('goog.events.EventTarget'); -goog.require('goog.events.EventType'); -goog.require('goog.json'); -goog.require('goog.net.ErrorCode'); -goog.require('goog.net.EventType'); -goog.require('goog.reflect'); -goog.require('goog.string'); -goog.require('goog.structs'); -goog.require('goog.userAgent'); - - - -/** - * Class for managing requests via iFrames. - * @constructor - * @extends {goog.events.EventTarget} - */ -goog.net.IframeIo = function() { - - /** - * Name for this IframeIo and frame - * @type {string} - * @private - */ - this.name_ = goog.net.IframeIo.getNextName_(); - - /** - * An array of iframes that have been finished with. We need them to be - * disposed async, so we don't confuse the browser (see below). - * @type {Array.<Element>} - * @private - */ - this.iframesForDisposal_ = []; - - // Create a lookup from names to instances of IframeIo. This is a helper - // function to be used in conjunction with goog.net.IframeIo.getInstanceByName - // to find the IframeIo object associated with a particular iframe. Used in - // incremental scripts etc. - goog.net.IframeIo.instances_[this.name_] = this; - -}; -goog.inherits(goog.net.IframeIo, goog.events.EventTarget); - - -/** - * Object used as a map to lookup instances of IframeIo objects by name. - * @type {Object} - * @private - */ -goog.net.IframeIo.instances_ = {}; - - -/** - * Prefix for frame names - * @type {string} - */ -goog.net.IframeIo.FRAME_NAME_PREFIX = 'closure_frame'; - - -/** - * Suffix that is added to inner frames used for sending requests in non-IE - * browsers - * @type {string} - */ -goog.net.IframeIo.INNER_FRAME_SUFFIX = '_inner'; - - -/** - * The number of milliseconds after a request is completed to dispose the - * iframes. This can be done lazily so we wait long enough for any processing - * that occurred as a result of the response to finish. - * @type {number} - */ -goog.net.IframeIo.IFRAME_DISPOSE_DELAY_MS = 2000; - - -/** - * Counter used when creating iframes - * @type {number} - * @private - */ -goog.net.IframeIo.counter_ = 0; - - -/** - * Form element to post to. - * @type {HTMLFormElement} - * @private - */ -goog.net.IframeIo.form_; - - -/** - * Static send that creates a short lived instance of IframeIo to send the - * request. - * @param {goog.Uri|string} uri Uri of the request, it is up the caller to - * manage query string params. - * @param {Function=} opt_callback Event handler for when request is completed. - * @param {string=} opt_method Default is GET, POST uses a form to submit the - * request. - * @param {boolean=} opt_noCache Append a timestamp to the request to avoid - * caching. - * @param {Object|goog.structs.Map=} opt_data Map of key-value pairs that - * will be posted to the server via the iframe's form. - */ -goog.net.IframeIo.send = function( - uri, opt_callback, opt_method, opt_noCache, opt_data) { - - var io = new goog.net.IframeIo(); - goog.events.listen(io, goog.net.EventType.READY, io.dispose, false, io); - if (opt_callback) { - goog.events.listen(io, goog.net.EventType.COMPLETE, opt_callback); - } - io.send(uri, opt_method, opt_noCache, opt_data); -}; - - -/** - * Find an iframe by name (assumes the context is goog.global since that is - * where IframeIo's iframes are kept). - * @param {string} fname The name to find. - * @return {HTMLIFrameElement} The iframe element with that name. - */ -goog.net.IframeIo.getIframeByName = function(fname) { - return window.frames[fname]; -}; - - -/** - * Find an instance of the IframeIo object by name. - * @param {string} fname The name to find. - * @return {goog.net.IframeIo} The instance of IframeIo. - */ -goog.net.IframeIo.getInstanceByName = function(fname) { - return goog.net.IframeIo.instances_[fname]; -}; - - -/** - * Handles incremental data and routes it to the correct iframeIo instance. - * The HTML page requested by the IframeIo instance should contain script blocks - * that call an externed reference to this method. - * @param {Window} win The window object. - * @param {Object} data The data object. - */ -goog.net.IframeIo.handleIncrementalData = function(win, data) { - // If this is the inner-frame, then we need to use the parent instead. - var iframeName = goog.string.endsWith(win.name, - goog.net.IframeIo.INNER_FRAME_SUFFIX) ? win.parent.name : win.name; - - var iframeIoName = iframeName.substring(0, iframeName.lastIndexOf('_')); - var iframeIo = goog.net.IframeIo.getInstanceByName(iframeIoName); - if (iframeIo && iframeName == iframeIo.iframeName_) { - iframeIo.handleIncrementalData_(data); - } else { - goog.debug.Logger.getLogger('goog.net.IframeIo').info( - 'Incremental iframe data routed for unknown iframe'); - } -}; - - -/** - * @return {string} The next iframe name. - * @private - */ -goog.net.IframeIo.getNextName_ = function() { - return goog.net.IframeIo.FRAME_NAME_PREFIX + goog.net.IframeIo.counter_++; -}; - - -/** - * Gets a static form, one for all instances of IframeIo since IE6 leaks form - * nodes that are created/removed from the document. - * @return {HTMLFormElement} The static form. - * @private - */ -goog.net.IframeIo.getForm_ = function() { - if (!goog.net.IframeIo.form_) { - goog.net.IframeIo.form_ = - /** @type {HTMLFormElement} */(goog.dom.createDom('form')); - goog.net.IframeIo.form_.acceptCharset = 'utf-8'; - - // Hide the form and move it off screen - var s = goog.net.IframeIo.form_.style; - s.position = 'absolute'; - s.visibility = 'hidden'; - s.top = s.left = '-10px'; - s.width = s.height = '10px'; - s.overflow = 'hidden'; - - goog.dom.getDocument().body.appendChild(goog.net.IframeIo.form_); - } - return goog.net.IframeIo.form_; -}; - - -/** - * Adds the key value pairs from a map like data structure to a form - * @param {HTMLFormElement} form The form to add to. - * @param {Object|goog.structs.Map|goog.Uri.QueryData} data The data to add. - * @private - */ -goog.net.IframeIo.addFormInputs_ = function(form, data) { - goog.structs.forEach(data, function(value, key) { - var inp = goog.dom.createDom('input', - {'type': 'hidden', 'name': key, 'value': value}); - form.appendChild(inp); - }); -}; - - -/** - * Reference to a logger for the IframeIo objects - * @type {goog.debug.Logger} - * @private - */ -goog.net.IframeIo.prototype.logger_ = - goog.debug.Logger.getLogger('goog.net.IframeIo'); - - -/** - * Reference to form element that gets reused for requests to the iframe. - * @type {HTMLFormElement} - * @private - */ -goog.net.IframeIo.prototype.form_ = null; - - -/** - * Reference to the iframe being used for the current request, or null if no - * request is currently active. - * @type {HTMLIFrameElement} - * @private - */ -goog.net.IframeIo.prototype.iframe_ = null; - - -/** - * Name of the iframe being used for the current request, or null if no - * request is currently active. - * @type {?string} - * @private - */ -goog.net.IframeIo.prototype.iframeName_ = null; - - -/** - * Next id so that iframe names are unique. - * @type {number} - * @private - */ -goog.net.IframeIo.prototype.nextIframeId_ = 0; - - -/** - * Whether the object is currently active with a request. - * @type {boolean} - * @private - */ -goog.net.IframeIo.prototype.active_ = false; - - -/** - * Whether the last request is complete. - * @type {boolean} - * @private - */ -goog.net.IframeIo.prototype.complete_ = false; - - -/** - * Whether the last request was a success. - * @type {boolean} - * @private - */ -goog.net.IframeIo.prototype.success_ = false; - - -/** - * The URI for the last request. - * @type {goog.Uri} - * @private - */ -goog.net.IframeIo.prototype.lastUri_ = null; - - -/** - * The text content of the last request. - * @type {?string} - * @private - */ -goog.net.IframeIo.prototype.lastContent_ = null; - - -/** - * Last error code - * @type {goog.net.ErrorCode} - * @private - */ -goog.net.IframeIo.prototype.lastErrorCode_ = goog.net.ErrorCode.NO_ERROR; - - -/** - * Number of milliseconds after which an incomplete request will be aborted and - * a {@link goog.net.EventType.TIMEOUT} event raised; 0 means no timeout is set. - * @type {number} - * @private - */ -goog.net.IframeIo.prototype.timeoutInterval_ = 0; - - -/** - * Window timeout ID used to cancel the timeout event handler if the request - * completes successfully. - * @type {?number} - * @private - */ -goog.net.IframeIo.prototype.timeoutId_ = null; - - -/** - * Window timeout ID used to detect when firefox silently fails. - * @type {?number} - * @private - */ -goog.net.IframeIo.prototype.firefoxSilentErrorTimeout_ = null; - - -/** - * Window timeout ID used by the timer that disposes the iframes. - * @type {?number} - * @private - */ -goog.net.IframeIo.prototype.iframeDisposalTimer_ = null; - - -/** - * This is used to ensure that we don't handle errors twice for the same error. - * We can reach the {@link #handleError_} method twice in IE if the form is - * submitted while IE is offline and the URL is not available. - * @type {boolean} - * @private - */ -goog.net.IframeIo.prototype.errorHandled_; - - -/** - * Sends a request via an iframe. - * - * A HTML form is used and submitted to the iframe, this simplifies the - * difference between GET and POST requests. The iframe needs to be created and - * destroyed for each request otherwise the request will contribute to the - * history stack. - * - * sendFromForm does some clever trickery (thanks jlim) in non-IE browsers to - * stop a history entry being added for POST requests. - * - * @param {goog.Uri|string} uri Uri of the request. - * @param {string=} opt_method Default is GET, POST uses a form to submit the - * request. - * @param {boolean=} opt_noCache Append a timestamp to the request to avoid - * caching. - * @param {Object|goog.structs.Map=} opt_data Map of key-value pairs. - */ -goog.net.IframeIo.prototype.send = function( - uri, opt_method, opt_noCache, opt_data) { - - if (this.active_) { - throw Error('[goog.net.IframeIo] Unable to send, already active.'); - } - - var uriObj = new goog.Uri(uri); - this.lastUri_ = uriObj; - var method = opt_method ? opt_method.toUpperCase() : 'GET'; - - if (opt_noCache) { - uriObj.makeUnique(); - } - - this.logger_.info('Sending iframe request: ' + uriObj + ' [' + method + ']'); - - // Build a form for this request - this.form_ = goog.net.IframeIo.getForm_(); - - if (method == 'GET') { - // For GET requests, we assume that the caller didn't want the queryparams - // already specified in the URI to be clobbered by the form, so we add the - // params here. - goog.net.IframeIo.addFormInputs_(this.form_, uriObj.getQueryData()); - } - - if (opt_data) { - // Create form fields for each of the data values - goog.net.IframeIo.addFormInputs_(this.form_, opt_data); - } - - // Set the URI that the form will be posted - this.form_.action = uriObj.toString(); - this.form_.method = method; - - this.sendFormInternal_(); -}; - - -/** - * Sends the data stored in an existing form to the server. The HTTP method - * should be specified on the form, the action can also be specified but can - * be overridden by the optional URI param. - * - * This can be used in conjunction will a file-upload input to upload a file in - * the background without affecting history. - * - * Example form: - * <pre> - * <form action="/server/" enctype="multipart/form-data" method="POST"> - * <input name="userfile" type="file"> - * </form> - * </pre> - * - * @param {HTMLFormElement} form Form element used to send the request to the - * server. - * @param {string=} opt_uri Uri to set for the destination of the request, by - * default the uri will come from the form. - * @param {boolean=} opt_noCache Append a timestamp to the request to avoid - * caching. - */ -goog.net.IframeIo.prototype.sendFromForm = function(form, opt_uri, - opt_noCache) { - if (this.active_) { - throw Error('[goog.net.IframeIo] Unable to send, already active.'); - } - - var uri = new goog.Uri(opt_uri || form.action); - if (opt_noCache) { - uri.makeUnique(); - } - - this.logger_.info('Sending iframe request from form: ' + uri); - - this.lastUri_ = uri; - this.form_ = form; - this.form_.action = uri.toString(); - this.sendFormInternal_(); -}; - - -/** - * Abort the current Iframe request - * @param {goog.net.ErrorCode=} opt_failureCode Optional error code to use - - * defaults to ABORT. - */ -goog.net.IframeIo.prototype.abort = function(opt_failureCode) { - if (this.active_) { - this.logger_.info('Request aborted'); - goog.events.removeAll(this.getRequestIframe_()); - this.complete_ = false; - this.active_ = false; - this.success_ = false; - this.lastErrorCode_ = opt_failureCode || goog.net.ErrorCode.ABORT; - - this.dispatchEvent(goog.net.EventType.ABORT); - - this.makeReady_(); - } -}; - - -/** @override */ -goog.net.IframeIo.prototype.disposeInternal = function() { - this.logger_.fine('Disposing iframeIo instance'); - - // If there is an active request, abort it - if (this.active_) { - this.logger_.fine('Aborting active request'); - this.abort(); - } - - // Call super-classes implementation (remove listeners) - goog.net.IframeIo.superClass_.disposeInternal.call(this); - - // Add the current iframe to the list of iframes for disposal. - if (this.iframe_) { - this.scheduleIframeDisposal_(); - } - - // Disposes of the form - this.disposeForm_(); - - // Nullify anything that might cause problems and clear state - delete this.errorChecker_; - this.form_ = null; - this.lastCustomError_ = this.lastContent_ = this.lastContentHtml_ = null; - this.lastUri_ = null; - this.lastErrorCode_ = goog.net.ErrorCode.NO_ERROR; - - delete goog.net.IframeIo.instances_[this.name_]; -}; - - -/** - * @return {boolean} True if transfer is complete. - */ -goog.net.IframeIo.prototype.isComplete = function() { - return this.complete_; -}; - - -/** - * @return {boolean} True if transfer was successful. - */ -goog.net.IframeIo.prototype.isSuccess = function() { - return this.success_; -}; - - -/** - * @return {boolean} True if a transfer is in progress. - */ -goog.net.IframeIo.prototype.isActive = function() { - return this.active_; -}; - - -/** - * Returns the last response text (i.e. the text content of the iframe). - * Assumes plain text! - * @return {?string} Result from the server. - */ -goog.net.IframeIo.prototype.getResponseText = function() { - return this.lastContent_; -}; - - -/** - * Returns the last response html (i.e. the innerHtml of the iframe). - * @return {?string} Result from the server. - */ -goog.net.IframeIo.prototype.getResponseHtml = function() { - return this.lastContentHtml_; -}; - - -/** - * Parses the content as JSON. This is a safe parse and may throw an error - * if the response is malformed. - * Use goog.json.unsafeparse(this.getResponseText()) if you are sure of the - * state of the returned content. - * @return {Object} The parsed content. - */ -goog.net.IframeIo.prototype.getResponseJson = function() { - return goog.json.parse(this.lastContent_); -}; - - -/** - * Returns the document object from the last request. Not truely XML, but - * used to mirror the XhrIo interface. - * @return {HTMLDocument} The document object from the last request. - */ -goog.net.IframeIo.prototype.getResponseXml = function() { - if (!this.iframe_) return null; - - return this.getContentDocument_(); -}; - - -/** - * Get the uri of the last request. - * @return {goog.Uri} Uri of last request. - */ -goog.net.IframeIo.prototype.getLastUri = function() { - return this.lastUri_; -}; - - -/** - * Gets the last error code. - * @return {goog.net.ErrorCode} Last error code. - */ -goog.net.IframeIo.prototype.getLastErrorCode = function() { - return this.lastErrorCode_; -}; - - -/** - * Gets the last error message. - * @return {string} Last error message. - */ -goog.net.IframeIo.prototype.getLastError = function() { - return goog.net.ErrorCode.getDebugMessage(this.lastErrorCode_); -}; - - -/** - * Gets the last custom error. - * @return {Object} Last custom error. - */ -goog.net.IframeIo.prototype.getLastCustomError = function() { - return this.lastCustomError_; -}; - - -/** - * Sets the callback function used to check if a loaded IFrame is in an error - * state. - * @param {Function} fn Callback that expects a document object as it's single - * argument. - */ -goog.net.IframeIo.prototype.setErrorChecker = function(fn) { - this.errorChecker_ = fn; -}; - - -/** - * Gets the callback function used to check if a loaded IFrame is in an error - * state. - * @return {Function} A callback that expects a document object as it's single - * argument. - */ -goog.net.IframeIo.prototype.getErrorChecker = function() { - return this.errorChecker_; -}; - - -/** - * Returns the number of milliseconds after which an incomplete request will be - * aborted, or 0 if no timeout is set. - * @return {number} Timeout interval in milliseconds. - */ -goog.net.IframeIo.prototype.getTimeoutInterval = function() { - return this.timeoutInterval_; -}; - - -/** - * Sets the number of milliseconds after which an incomplete request will be - * aborted and a {@link goog.net.EventType.TIMEOUT} event raised; 0 means no - * timeout is set. - * @param {number} ms Timeout interval in milliseconds; 0 means none. - */ -goog.net.IframeIo.prototype.setTimeoutInterval = function(ms) { - // TODO (pupius) - never used - doesn't look like timeouts were implemented - this.timeoutInterval_ = Math.max(0, ms); -}; - - -/** - * Submits the internal form to the iframe. - * @private - */ -goog.net.IframeIo.prototype.sendFormInternal_ = function() { - this.active_ = true; - this.complete_ = false; - this.lastErrorCode_ = goog.net.ErrorCode.NO_ERROR; - - // Make Iframe - this.createIframe_(); - - if (goog.userAgent.IE) { - // In IE we simply create the frame, wait until it is ready, then post the - // form to the iframe and wait for the readystate to change to 'complete' - - // Set the target to the iframe's name - this.form_.target = this.iframeName_ || ''; - this.appendIframe_(); - goog.events.listen(this.iframe_, goog.events.EventType.READYSTATECHANGE, - this.onIeReadyStateChange_, false, this); - - /** @preserveTry */ - try { - this.errorHandled_ = false; - this.form_.submit(); - } catch (e) { - // If submit threw an exception then it probably means the page that the - // code is running on the local file system and the form's action was - // pointing to a file that doesn't exist, causing the browser to fire an - // exception. IE also throws an exception when it is working offline and - // the URL is not available. - - goog.events.unlisten(this.iframe_, goog.events.EventType.READYSTATECHANGE, - this.onIeReadyStateChange_, false, this); - - this.handleError_(goog.net.ErrorCode.ACCESS_DENIED); - } - - } else { - // For all other browsers we do some trickery to ensure that there is no - // entry on the history stack. Thanks go to jlim for the prototype for this - - this.logger_.fine('Setting up iframes and cloning form'); - - this.appendIframe_(); - - var innerFrameName = this.iframeName_ + - goog.net.IframeIo.INNER_FRAME_SUFFIX; - - // Open and document.write another iframe into the iframe - var doc = goog.dom.getFrameContentDocument(this.iframe_); - var html = '<body><iframe id=' + innerFrameName + - ' name=' + innerFrameName + '></iframe>'; - if (document.baseURI) { - // On Safari 4 and 5 the new iframe doesn't inherit the current baseURI. - html = '<head><base href="' + goog.string.htmlEscape(document.baseURI) + - '"></head>' + html; - } - if (goog.userAgent.OPERA) { - // Opera adds a history entry when document.write is used. - // Change the innerHTML of the page instead. - doc.documentElement.innerHTML = html; - } else { - doc.write(html); - } - - // Listen for the iframe's load - goog.events.listen(doc.getElementById(innerFrameName), - goog.events.EventType.LOAD, this.onIframeLoaded_, false, this); - - // Fix text areas, since importNode won't clone changes to the value - var textareas = this.form_.getElementsByTagName('textarea'); - for (var i = 0, n = textareas.length; i < n; i++) { - // The childnodes represent the initial child nodes for the text area - // appending a text node essentially resets the initial value ready for - // it to be clones - while maintaining HTML escaping. - var value = textareas[i].value; - if (goog.dom.getRawTextContent(textareas[i]) != value) { - goog.dom.setTextContent(textareas[i], value); - textareas[i].value = value; - } - } - - // Append a cloned form to the iframe - var clone = doc.importNode(this.form_, true); - clone.target = innerFrameName; - // Work around crbug.com/66987 - clone.action = this.form_.action; - doc.body.appendChild(clone); - - // Fix select boxes, importNode won't override the default value - var selects = this.form_.getElementsByTagName('select'); - var clones = clone.getElementsByTagName('select'); - for (var i = 0, n = selects.length; i < n; i++) { - var selectsOptions = selects[i].getElementsByTagName('option'); - var clonesOptions = clones[i].getElementsByTagName('option'); - for (var j = 0, m = selectsOptions.length; j < m; j++) { - clonesOptions[j].selected = selectsOptions[j].selected; - } - } - - // Some versions of Firefox (1.5 - 1.5.07?) fail to clone the value - // attribute for <input type="file"> nodes, which results in an empty - // upload if the clone is submitted. Check, and if the clone failed, submit - // using the original form instead. - var inputs = this.form_.getElementsByTagName('input'); - var inputClones = clone.getElementsByTagName('input'); - for (var i = 0, n = inputs.length; i < n; i++) { - if (inputs[i].type == 'file') { - if (inputs[i].value != inputClones[i].value) { - this.logger_.fine('File input value not cloned properly. Will ' + - 'submit using original form.'); - this.form_.target = innerFrameName; - clone = this.form_; - break; - } - } - } - - this.logger_.fine('Submitting form'); - - /** @preserveTry */ - try { - this.errorHandled_ = false; - clone.submit(); - doc.close(); - - if (goog.userAgent.GECKO) { - // This tests if firefox silently fails, this can happen, for example, - // when the server resets the connection because of a large file upload - this.firefoxSilentErrorTimeout_ = - goog.Timer.callOnce(this.testForFirefoxSilentError_, 250, this); - } - - } catch (e) { - // If submit threw an exception then it probably means the page that the - // code is running on the local file system and the form's action was - // pointing to a file that doesn't exist, causing the browser to fire an - // exception. - - this.logger_.severe( - 'Error when submitting form: ' + goog.debug.exposeException(e)); - - goog.events.unlisten(doc.getElementById(innerFrameName), - goog.events.EventType.LOAD, this.onIframeLoaded_, false, this); - - doc.close(); - - this.handleError_(goog.net.ErrorCode.FILE_NOT_FOUND); - } - } -}; - - -/** - * Handles the load event of the iframe for IE, determines if the request was - * successful or not, handles clean up and dispatching of appropriate events. - * @param {goog.events.BrowserEvent} e The browser event. - * @private - */ -goog.net.IframeIo.prototype.onIeReadyStateChange_ = function(e) { - if (this.iframe_.readyState == 'complete') { - goog.events.unlisten(this.iframe_, goog.events.EventType.READYSTATECHANGE, - this.onIeReadyStateChange_, false, this); - var doc; - /** @preserveTry */ - try { - doc = goog.dom.getFrameContentDocument(this.iframe_); - - // IE serves about:blank when it cannot load the resource while offline. - if (goog.userAgent.IE && doc.location == 'about:blank' && - !navigator.onLine) { - this.handleError_(goog.net.ErrorCode.OFFLINE); - return; - } - } catch (ex) { - this.handleError_(goog.net.ErrorCode.ACCESS_DENIED); - return; - } - this.handleLoad_(/** @type {HTMLDocument} */(doc)); - } -}; - - -/** - * Handles the load event of the iframe for non-IE browsers. - * @param {goog.events.BrowserEvent} e The browser event. - * @private - */ -goog.net.IframeIo.prototype.onIframeLoaded_ = function(e) { - // In Opera, the default "about:blank" page of iframes fires an onload - // event that we'd like to ignore. - if (goog.userAgent.OPERA && - this.getContentDocument_().location == 'about:blank') { - return; - } - goog.events.unlisten(this.getRequestIframe_(), - goog.events.EventType.LOAD, this.onIframeLoaded_, false, this); - this.handleLoad_(this.getContentDocument_()); -}; - - -/** - * Handles generic post-load - * @param {HTMLDocument} contentDocument The frame's document. - * @private - */ -goog.net.IframeIo.prototype.handleLoad_ = function(contentDocument) { - this.logger_.fine('Iframe loaded'); - - this.complete_ = true; - this.active_ = false; - - var errorCode; - - // Try to get the innerHTML. If this fails then it can be an access denied - // error or the document may just not have a body, typical case is if there - // is an IE's default 404. - /** @preserveTry */ - try { - var body = contentDocument.body; - this.lastContent_ = body.textContent || body.innerText; - this.lastContentHtml_ = body.innerHTML; - } catch (ex) { - errorCode = goog.net.ErrorCode.ACCESS_DENIED; - } - - // Use a callback function, defined by the application, to analyse the - // contentDocument and determine if it is an error page. Applications - // may send down markers in the document, define JS vars, or some other test. - var customError; - if (!errorCode && typeof this.errorChecker_ == 'function') { - customError = this.errorChecker_(contentDocument); - if (customError) { - errorCode = goog.net.ErrorCode.CUSTOM_ERROR; - } - } - - this.logger_.finer('Last content: ' + this.lastContent_); - this.logger_.finer('Last uri: ' + this.lastUri_); - - if (errorCode) { - this.logger_.fine('Load event occurred but failed'); - this.handleError_(errorCode, customError); - - } else { - this.logger_.fine('Load succeeded'); - this.success_ = true; - this.lastErrorCode_ = goog.net.ErrorCode.NO_ERROR; - this.dispatchEvent(goog.net.EventType.COMPLETE); - this.dispatchEvent(goog.net.EventType.SUCCESS); - - this.makeReady_(); - } -}; - - -/** - * Handles errors. - * @param {goog.net.ErrorCode} errorCode Error code. - * @param {Object=} opt_customError If error is CUSTOM_ERROR, this is the - * client-provided custom error. - * @private - */ -goog.net.IframeIo.prototype.handleError_ = function(errorCode, - opt_customError) { - if (!this.errorHandled_) { - this.success_ = false; - this.active_ = false; - this.complete_ = true; - this.lastErrorCode_ = errorCode; - if (errorCode == goog.net.ErrorCode.CUSTOM_ERROR) { - this.lastCustomError_ = opt_customError; - } - this.dispatchEvent(goog.net.EventType.COMPLETE); - this.dispatchEvent(goog.net.EventType.ERROR); - - this.makeReady_(); - - this.errorHandled_ = true; - } -}; - - -/** - * Dispatches an event indicating that the IframeIo instance has received a data - * packet via incremental loading. The event object has a 'data' member. - * @param {Object} data Data. - * @private - */ -goog.net.IframeIo.prototype.handleIncrementalData_ = function(data) { - this.dispatchEvent(new goog.net.IframeIo.IncrementalDataEvent(data)); -}; - - -/** - * Finalizes the request, schedules the iframe for disposal, and maybe disposes - * the form. - * @private - */ -goog.net.IframeIo.prototype.makeReady_ = function() { - this.logger_.info('Ready for new requests'); - var iframe = this.iframe_; - this.scheduleIframeDisposal_(); - this.disposeForm_(); - this.dispatchEvent(goog.net.EventType.READY); -}; - - -/** - * Creates an iframe to be used with a request. We use a new iframe for each - * request so that requests don't create history entries. - * @private - */ -goog.net.IframeIo.prototype.createIframe_ = function() { - this.logger_.fine('Creating iframe'); - - this.iframeName_ = this.name_ + '_' + (this.nextIframeId_++).toString(36); - - var iframeAttributes = {'name': this.iframeName_, 'id': this.iframeName_}; - // Setting the source to javascript:"" is a fix to remove IE6 mixed content - // warnings when being used in an https page. - if (goog.userAgent.IE && goog.userAgent.VERSION < 7) { - iframeAttributes.src = 'javascript:""'; - } - - this.iframe_ = /** @type {HTMLIFrameElement} */(goog.dom.createDom( - 'iframe', iframeAttributes)); - - var s = this.iframe_.style; - s.visibility = 'hidden'; - s.width = s.height = '10px'; - - // There are reports that safari 2.0.3 has a bug where absolutely positioned - // iframes can't have their src set. - if (!goog.userAgent.WEBKIT) { - s.position = 'absolute'; - s.top = s.left = '-10px'; - } else { - s.marginTop = s.marginLeft = '-10px'; - } -}; - - -/** - * Appends the Iframe to the document body. - * @private - */ -goog.net.IframeIo.prototype.appendIframe_ = function() { - goog.dom.getDocument().body.appendChild(this.iframe_); -}; - - -/** - * Schedules an iframe for disposal, async. We can't remove the iframes in the - * same execution context as the response, otherwise some versions of Firefox - * will not detect that the response has correctly finished and the loading bar - * will stay active forever. - * @private - */ -goog.net.IframeIo.prototype.scheduleIframeDisposal_ = function() { - var iframe = this.iframe_; - - // There shouldn't be a case where the iframe is null and we get to this - // stage, but the error reports in http://b/909448 indicate it is possible. - if (iframe) { - // NOTE(user): Stops Internet Explorer leaking the iframe object. This - // shouldn't be needed, since the events have all been removed, which - // should in theory clean up references. Oh well... - iframe.onreadystatechange = null; - iframe.onload = null; - iframe.onerror = null; - - this.iframesForDisposal_.push(iframe); - } - - if (this.iframeDisposalTimer_) { - goog.Timer.clear(this.iframeDisposalTimer_); - this.iframeDisposalTimer_ = null; - } - - if (goog.userAgent.GECKO || goog.userAgent.OPERA) { - // For FF and Opera, we must dispose the iframe async, - // but it doesn't need to be done as soon as possible. - // We therefore schedule it for 2s out, so as not to - // affect any other actions that may have been triggered by the request. - this.iframeDisposalTimer_ = goog.Timer.callOnce( - this.disposeIframes_, goog.net.IframeIo.IFRAME_DISPOSE_DELAY_MS, this); - - } else { - // For non-Gecko browsers we dispose straight away. - this.disposeIframes_(); - } - - // Nullify reference - this.iframe_ = null; - this.iframeName_ = null; -}; - - -/** - * Disposes any iframes. - * @private - */ -goog.net.IframeIo.prototype.disposeIframes_ = function() { - if (this.iframeDisposalTimer_) { - // Clear the timer - goog.Timer.clear(this.iframeDisposalTimer_); - this.iframeDisposalTimer_ = null; - } - - while (this.iframesForDisposal_.length != 0) { - var iframe = this.iframesForDisposal_.pop(); - this.logger_.info('Disposing iframe'); - goog.dom.removeNode(iframe); - } -}; - - -/** - * Disposes of the Form. Since IE6 leaks form nodes, this just cleans up the - * DOM and nullifies the instances reference so the form can be used for another - * request. - * @private - */ -goog.net.IframeIo.prototype.disposeForm_ = function() { - if (this.form_ && this.form_ == goog.net.IframeIo.form_) { - goog.dom.removeChildren(this.form_); - } - this.form_ = null; -}; - - -/** - * @return {HTMLDocument} The appropriate content document. - * @private - */ -goog.net.IframeIo.prototype.getContentDocument_ = function() { - if (this.iframe_) { - return /** @type {HTMLDocument} */(goog.dom.getFrameContentDocument( - this.getRequestIframe_())); - } - return null; -}; - - -/** - * @return {HTMLIFrameElement} The appropriate iframe to use for requests - * (created in sendForm_). - * @private - */ -goog.net.IframeIo.prototype.getRequestIframe_ = function() { - if (this.iframe_) { - return /** @type {HTMLIFrameElement} */(goog.userAgent.IE ? this.iframe_ : - goog.dom.getFrameContentDocument(this.iframe_).getElementById( - this.iframeName_ + goog.net.IframeIo.INNER_FRAME_SUFFIX)); - } - return null; -}; - - -/** - * Tests for a silent failure by firefox that can occur when the connection is - * reset by the server or is made to an illegal URL. - * @private - */ -goog.net.IframeIo.prototype.testForFirefoxSilentError_ = function() { - if (this.active_) { - var doc = this.getContentDocument_(); - - // This is a hack to test of the document has loaded with a page that - // we can't access, such as a network error, that won't report onload - // or onerror events. - if (doc && !goog.reflect.canAccessProperty(doc, 'documentUri')) { - goog.events.unlisten(this.getRequestIframe_(), - goog.events.EventType.LOAD, this.onIframeLoaded_, false, this); - - if (navigator.onLine) { - this.logger_.warning('Silent Firefox error detected'); - this.handleError_(goog.net.ErrorCode.FF_SILENT_ERROR); - } else { - this.logger_.warning('Firefox is offline so report offline error ' + - 'instead of silent error'); - this.handleError_(goog.net.ErrorCode.OFFLINE); - } - return; - } - this.firefoxSilentErrorTimeout_ = - goog.Timer.callOnce(this.testForFirefoxSilentError_, 250, this); - } -}; - - - -/** - * Class for representing incremental data events. - * @param {Object} data The data associated with the event. - * @extends {goog.events.Event} - * @constructor - */ -goog.net.IframeIo.IncrementalDataEvent = function(data) { - goog.events.Event.call(this, goog.net.EventType.INCREMENTAL_DATA); - - /** - * The data associated with the event. - * @type {Object} - */ - this.data = data; -}; -goog.inherits(goog.net.IframeIo.IncrementalDataEvent, goog.events.Event); diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/iframeio_different_base_test.data.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/iframeio_different_base_test.data.svn-base deleted file mode 100644 index fed4357..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/iframeio_different_base_test.data.svn-base +++ /dev/null @@ -1,2 +0,0 @@ -This is just a file that iframeio_different_base_test.html requests to test -iframeIo. diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/iframeio_different_base_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/iframeio_different_base_test.html.svn-base deleted file mode 100644 index 476cbe8..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/iframeio_different_base_test.html.svn-base +++ /dev/null @@ -1,44 +0,0 @@ -<html> -<!-- -Copyright 2011 The Closure Library Authors. All Rights Reserved. - -Use of this source code is governed by the Apache License, Version 2.0. -See the COPYING file for details. ---> -<head> -<title>Closure Unit Tests - goog.net.IframeIo (with different base URL)</title> -<script> -// We use a different base to reproduce the conditions of crbug.com/66987 -var href = window.location.href; -var newHref = href.replace(/net.*/, ''); -document.write('<base href="' + newHref + '">'); - -var baseScript = 'base.js'; -document.write('<script src="' + baseScript + '"><\/script>'); -</script> -<script> - goog.require('goog.net.IframeIo'); - goog.require('goog.testing.AsyncTestCase'); - goog.require('goog.testing.jsunit'); -</script> -</head> -<body> -<script> - -var asyncTestCase = goog.testing.AsyncTestCase.createAndInstall(); - -function testDifferentBaseUri() { - var io = new goog.net.IframeIo(); - goog.events.listen(io, goog.net.EventType.COMPLETE, - function() { - assertNotEquals('File should have expected content.', - -1, io.getResponseText().indexOf('just a file')); - asyncTestCase.continueTesting(); - }); - io.send('net/iframeio_different_base_test.data'); - asyncTestCase.waitForAsync('Waiting for iframeIo respons.'); -} - -</script> -</body> -</html> diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/iframeio_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/iframeio_test.html.svn-base deleted file mode 100644 index f1e60e2..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/iframeio_test.html.svn-base +++ /dev/null @@ -1,374 +0,0 @@ -<!DOCTYPE html> -<html> -<!-- -Copyright 2006 The Closure Library Authors. All Rights Reserved. - -Use of this source code is governed by the Apache License, Version 2.0. -See the COPYING file for details. ---> -<head> -<meta http-equiv="X-UA-Compatible" content="IE=edge"> -<title>Closure Unit Tests - goog.net.IframeIo</title> -<script src="../base.js"></script> -<script> - goog.require('goog.debug.DivConsole'); - goog.require('goog.net.IframeIo'); - goog.require('goog.testing.jsunit'); -</script> -<style> - - html, body { - width: 100%; - height: 100%; - overflow:hidden; - } - - #log { - position: absolute; - top: 0px; - width: 50%; - right: 0%; - height: 100%; - overflow: auto; - } - - p, input { - font-family: verdana, helvetica, arial, sans-serif; - font-size: small; - margin: 0px; - } - - input { - font-family: verdana, helvetica, arial, sans-serif; - font-size: x-small; - } - - i { - font-size: 85%; - } - - -</style> -</head> -<body> -<p> - <b>IframeIo manual tests:</b><br><br> - <i>All operations should have no effect on history.</i><br> - <br> - <i>These tests require the ClosureTestServer<br> - to be running with the IframeIoTestServlet.</i><br> -<br></p> - -<p> - <a href="javascript:simpleGet()">Simple GET</a><br> - <a href="javascript:simplePost()">Simple POST</a><br> - <a href="javascript:jsonEcho('GET')">JSON echo (get)</a><br> - <a href="javascript:jsonEcho('POST')">JSON echo (post)</a><br> - <a href="javascript:abort()">Test abort</a> -</p> -<form id="uploadform" action="/iframeio/upload" enctype="multipart/form-data" method="POST"> - <p><a href="javascript:sendFromForm()">Upload</a> <input name="userfile" type="file"> (big files should fail)</p> -</form> -<p> - <a href="javascript:incremental()">Incremental results</a><br> - <a href="javascript:redirect1()">Redirect (google.com)</a><br> - <a href="javascript:redirect2()">Redirect (/iframeio/ping)</a><br> - <a href="javascript:localUrl1()">Local request (Win path)</a><br> - <a href="javascript:localUrl2()">Local request (Linux path)</a><br> - <a href="javascript:badUrl()">Out of domain request</a><br> - <a href="javascript:getServerTime(false)">Test cache</a> (Date should stay the same for subsequent tests)<br> - <a href="javascript:getServerTime(true)">Test no-cache</a><br> - <a href="javascript:errorGse404()">GSE 404 Error</a><br> - <a href="javascript:errorGfe()">Simulated GFE Error</a><br> - <a href="javascript:errorGmail()">Simulated Gmail Server Error</a><br><br> -</p> -<form id="testfrm" action="/iframeio/jsonecho" method="POST"> - <p><b>Comprehensive Form Post Test:</b><br> - <input name="textinput" type="text" value="Default"> Text Input<br> - Text Area<br> - <textarea name="textarea">Default</textarea><br> - <input name="checkbox1" type="checkbox" checked="checked"> Checkbox, default on<br> - <input name="checkbox2" type="checkbox"> Checkbox, default off<br> - Radio: <input name="radio" type="radio" value="Default" checked="checked"> Default, - <input name="radio" type="radio" value="Foo"> Foo, - <input name="radio" type="radio" value="Bar"> Bar<br> - <select name="select"> - <option>One</option> - <option>Two</option> - <option selected="selected">Three (Default)</option> - <option>Four</option> - <option>Five</option> - </select><br> - <select name="selectmultiple"> - <option>One</option> - <option selected="selected">Two (Default checked)</option> - <option selected="selected">Three (Default checked)</option> - <option>Four</option> - </select> - <a href="javascript:postForm()">Submit this form</a> - </p> -</form> -<p><br><br> -TODO(pupius):<br> -- Local timeout -</p> -<div id="log"></div> - -<script> -// MANUAL TESTS - The tests should be run in the browser from the Closure Test -// Server - -// Set up a logger to track responses -goog.debug.LogManager.getRoot().setLevel(goog.debug.Logger.Level.INFO); -var logconsole = new goog.debug.DivConsole(document.getElementById('log')); -logconsole.setCapturing(true); - -var testLogger = goog.debug.Logger.getLogger('test'); - - -/** Creates an iframeIo instance and sets up the test environment */ -function getTestIframeIo() { - logconsole.addSeparator(); - logconsole.getFormatter().resetRelativeTimeStart(); - - var io = new goog.net.IframeIo(); - io.setErrorChecker(checkForError); - - goog.events.listen(io, 'success', onSuccess); - goog.events.listen(io, 'error', onError); - goog.events.listen(io, 'ready', onReady); - - return io; -} - -/** - * Checks for error strings returned by the GSE and error variables that - * the Gmail server and GFE set on certain errors. - */ -function checkForError(doc) { - var win = goog.dom.getWindow(doc); - var text = doc.body.textContent || doc.body.innerText || ''; - var gseError = text.match(/([^\n]+)\nError ([0-9]{3})/); - if (gseError) { - return '(Error ' + gseError[2] + ') ' + gseError[1]; - } else if (win.gmail_error) { - return win.gmail_error + 700; - } else if (win.rc) { - return 600 + win.rc % 100; - } else { - return null; - } -} - -/** Logs the status of an iframeIo object */ -function logStatus(i) { - testLogger.fine('Is complete/success/active: ' + - [i.isComplete(), i.isSuccess(), i.isActive()].join('/')); -} - -function onSuccess(e) { - testLogger.warning('Request Succeeded'); - logStatus(e.target); -} - -function onError(e) { - testLogger.warning('Request Errored: ' + e.target.getLastError()); - logStatus(e.target); -} - -function onReady(e) { - testLogger.info('Test finished and iframe ready, disposing test object'); - e.target.dispose(); -} - - - -function simpleGet() { - var io = getTestIframeIo(); - goog.events.listen(io, 'complete', onSimpleTestComplete); - io.send('/iframeio/ping', 'GET'); -} - - -function simplePost() { - var io = getTestIframeIo(); - goog.events.listen(io, 'complete', onSimpleTestComplete); - io.send('/iframeio/ping', 'POST'); -} - -function onSimpleTestComplete(e) { - testLogger.info('ResponseText: ' + e.target.getResponseText()); -} - -function abort() { - var io = getTestIframeIo(); - goog.events.listen(io, 'complete', onAbortComplete); - goog.events.listen(io, 'abort', onAbort); - io.send('/iframeio/ping', 'GET'); - io.abort(); -} - -function onAbortComplete(e) { - testLogger.info('Hmm, request should have been aborted'); -} - -function onAbort(e) { - testLogger.info('Request aborted'); -} - - -function errorGse404() { - var io = getTestIframeIo(); - io.send('/iframeio/404', 'GET'); -} - -function jsonEcho(method) { - var io = getTestIframeIo(); - goog.events.listen(io, 'complete', onJsonComplete); - var data = {'p1': 'x', 'p2': 'y', 'p3': 'z', 'r': 10}; - io.send('/iframeio/jsonecho?q1=a&q2=b&q3=c&r=5', method, false, data); -} - -function onJsonComplete(e) { - testLogger.info('ResponseText: ' + e.target.getResponseText()); - var json = e.target.getResponseJson(); - testLogger.info('ResponseJson:\n' + goog.debug.deepExpose(json, true)); -} - - - -function sendFromForm() { - var io = getTestIframeIo() - goog.events.listen(io, 'success', onUploadSuccess); - goog.events.listen(io, 'error', onUploadError); - io.sendFromForm(document.getElementById('uploadform')); -} - -function onUploadSuccess(e) { - testLogger.shout('Upload Succeeded'); - testLogger.info('ResponseText: ' + e.target.getResponseText()); -} - -function onUploadError(e) { - testLogger.shout('Upload Errored'); - testLogger.info('ResponseText: ' + e.target.getResponseText()); -} - - -function redirect1() { - var io = getTestIframeIo(); - io.send('/iframeio/redirect', 'GET'); -} - -function redirect2() { - var io = getTestIframeIo(); - io.send('/iframeio/move', 'GET'); -} - -function badUrl() { - var io = getTestIframeIo(); - io.send('http://news.bbc.co.uk', 'GET'); -} - -function localUrl1() { - var io = getTestIframeIo(); - goog.events.listen(io, 'complete', onLocalSuccess); - io.send('c:\test.txt', 'GET'); -} - -function localUrl2() { - var io = getTestIframeIo(); - goog.events.listen(io, 'success', onLocalSuccess); - io.send('//test.txt', 'GET'); -} - -function onLocalSuccess(e) { - testLogger.info('The file was found:\n' + e.target.getResponseText()); -} - -function getServerTime(noCache) { - var io = getTestIframeIo(); - goog.events.listen(io, 'success', onTestCacheSuccess); - io.send('/iframeio/datetime', 'GET', noCache); -} - -function onTestCacheSuccess(e) { - testLogger.info('Date reported: ' + e.target.getResponseText()); -} - - -function errorGmail() { - var io = getTestIframeIo(); - goog.events.listen(io, 'error', onGmailError); - io.send('/iframeio/gmailerror', 'GET'); -} - -function onGmailError(e) { - testLogger.info('Gmail error: ' + e.target.getLastError()); -} - - -function errorGfe() { - var io = getTestIframeIo(); - goog.events.listen(io, 'error', onGfeError); - io.send('/iframeio/gfeerror', 'GET'); -} - -function onGfeError(e) { - testLogger.info('GFE error: ' + e.target.getLastError()); -} - - - -function incremental() { - var io = getTestIframeIo(); - io.send('/iframeio/incremental', 'GET'); -} - -window['P'] = function(iframe, data) { - var iframeIo = goog.net.IframeIo.getInstanceByName(iframe.name); - testLogger.info('Data recieved - ' + data); -}; - - -function postForm() { - var io = getTestIframeIo() - goog.events.listen(io, 'complete', onJsonComplete); - io.sendFromForm(document.getElementById('testfrm')); -} - -</script> - - - -<script> -// UNIT TESTS - to be run via the JsUnit testRunner - -// TODO(user): How to unit test all of this? Creating a MockIframe could -// help for the IE code path, but since the other browsers require weird -// behaviors this becomes very tricky. - - -function testGetForm() { - var frm1 = goog.net.IframeIo.getForm_; - var frm2 = goog.net.IframeIo.getForm_; - assertEquals(frm1, frm2); -} - - -function testAddFormInputs() { - var form = document.createElement('form'); - goog.net.IframeIo.addFormInputs_(form, {'a': 1, 'b': 2, 'c': 3}); - var inputs = form.getElementsByTagName('input'); - assertEquals(3, inputs.length); - for (var i = 0; i < inputs.length; i++) { - assertEquals('hidden', inputs[i].type); - var n = inputs[i].name; - assertEquals(n == 'a' ? '1' : n == 'b' ? '2' : '3', inputs[i].value); - } -} - -</script> - -</body> -</html> diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/iframeloadmonitor.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/iframeloadmonitor.js.svn-base deleted file mode 100644 index df08a59..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/iframeloadmonitor.js.svn-base +++ /dev/null @@ -1,200 +0,0 @@ -// Copyright 2008 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Class that can be used to determine when an iframe is loaded. - */ - -goog.provide('goog.net.IframeLoadMonitor'); - -goog.require('goog.dom'); -goog.require('goog.events'); -goog.require('goog.events.EventTarget'); -goog.require('goog.events.EventType'); -goog.require('goog.userAgent'); - - - -/** - * The correct way to determine whether an iframe has completed loading - * is different in IE and Firefox. This class abstracts above these - * differences, providing a consistent interface for: - * <ol> - * <li> Determing if an iframe is currently loaded - * <li> Listening for an iframe that is not currently loaded, to finish loading - * </ol> - * - * @param {HTMLIFrameElement} iframe An iframe. - * @param {boolean=} opt_hasContent Does the loaded iframe have content. - * @extends {goog.events.EventTarget} - * @constructor - */ -goog.net.IframeLoadMonitor = function(iframe, opt_hasContent) { - goog.base(this); - - /** - * Iframe whose load state is monitored by this IframeLoadMonitor - * @type {HTMLIFrameElement} - * @private - */ - this.iframe_ = iframe; - - /** - * Whether or not the loaded iframe has any content. - * @type {boolean} - * @private - */ - this.hasContent_ = !!opt_hasContent; - - /** - * Whether or not the iframe is loaded. - * @type {boolean} - * @private - */ - this.isLoaded_ = this.isLoadedHelper_(); - - if (!this.isLoaded_) { - // IE 6 (and lower?) does not reliably fire load events, so listen to - // readystatechange. - // IE 7 does not reliably fire readystatechange events but listening on load - // seems to work just fine. - var isIe6OrLess = goog.userAgent.IE && !goog.userAgent.isVersion('7'); - var loadEvtType = isIe6OrLess ? - goog.events.EventType.READYSTATECHANGE : goog.events.EventType.LOAD; - this.onloadListenerKey_ = goog.events.listen( - this.iframe_, loadEvtType, this.handleLoad_, false, this); - - // Sometimes we still don't get the event callback, so we'll poll just to - // be safe. - this.intervalId_ = window.setInterval( - goog.bind(this.handleLoad_, this), - goog.net.IframeLoadMonitor.POLL_INTERVAL_MS_); - } -}; -goog.inherits(goog.net.IframeLoadMonitor, goog.events.EventTarget); - - -/** - * Event type dispatched by a goog.net.IframeLoadMonitor when it internal iframe - * finishes loading for the first time after construction of the - * goog.net.IframeLoadMonitor - * @type {string} - */ -goog.net.IframeLoadMonitor.LOAD_EVENT = 'ifload'; - - -/** - * Poll interval for polling iframe load states in milliseconds. - * @type {number} - * @private - */ -goog.net.IframeLoadMonitor.POLL_INTERVAL_MS_ = 100; - - -/** - * Key for iframe load listener, or null if not currently listening on the - * iframe for a load event. - * @type {?number} - * @private - */ -goog.net.IframeLoadMonitor.prototype.onloadListenerKey_ = null; - - -/** - * Returns whether or not the iframe is loaded. - * @return {boolean} whether or not the iframe is loaded. - */ -goog.net.IframeLoadMonitor.prototype.isLoaded = function() { - return this.isLoaded_; -}; - - -/** - * Stops the poll timer if this IframeLoadMonitor is currently polling. - * @private - */ -goog.net.IframeLoadMonitor.prototype.maybeStopTimer_ = function() { - if (this.intervalId_) { - window.clearInterval(this.intervalId_); - this.intervalId_ = null; - } -}; - - -/** - * Returns the iframe whose load state this IframeLoader monitors. - * @return {HTMLIFrameElement} the iframe whose load state this IframeLoader - * monitors. - */ -goog.net.IframeLoadMonitor.prototype.getIframe = function() { - return this.iframe_; -}; - - -/** @override */ -goog.net.IframeLoadMonitor.prototype.disposeInternal = function() { - delete this.iframe_; - this.maybeStopTimer_(); - goog.events.unlistenByKey(this.onloadListenerKey_); - goog.net.IframeLoadMonitor.superClass_.disposeInternal.call(this); -}; - - -/** - * Returns whether or not the iframe is loaded. Determines this by inspecting - * browser dependent properties of the iframe. - * @return {boolean} whether or not the iframe is loaded. - * @private - */ -goog.net.IframeLoadMonitor.prototype.isLoadedHelper_ = function() { - var isLoaded = false; - /** @preserveTry */ - try { - // IE will reliably have readyState set to complete if the iframe is loaded - // For everything else, the iframe is loaded if there is a body and if the - // body should have content the firstChild exists. Firefox can fire - // the LOAD event and then a few hundred ms later replace the - // contentDocument once the content is loaded. - isLoaded = goog.userAgent.IE ? this.iframe_.readyState == 'complete' : - !!goog.dom.getFrameContentDocument(this.iframe_).body && - (!this.hasContent_ || - !!goog.dom.getFrameContentDocument(this.iframe_).body.firstChild); - } catch (e) { - // Ignore these errors. This just means that the iframe is not loaded - // IE will throw error reading readyState if the iframe is not appended - // to the dom yet. - // Firefox will throw error getting the iframe body if the iframe is not - // fully loaded. - } - return isLoaded; -}; - - -/** - * Handles an event indicating that the loading status of the iframe has - * changed. In Firefox this is a goog.events.EventType.LOAD event, in IE - * this is a goog.events.EventType.READYSTATECHANGED - * @private - */ -goog.net.IframeLoadMonitor.prototype.handleLoad_ = function() { - // Only do the handler if the iframe is loaded. - if (this.isLoadedHelper_()) { - this.maybeStopTimer_(); - goog.events.unlistenByKey(this.onloadListenerKey_); - this.onloadListenerKey_ = null; - this.isLoaded_ = true; - this.dispatchEvent(goog.net.IframeLoadMonitor.LOAD_EVENT); - } -}; - diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/iframeloadmonitor_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/iframeloadmonitor_test.html.svn-base deleted file mode 100644 index 501d477..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/iframeloadmonitor_test.html.svn-base +++ /dev/null @@ -1,113 +0,0 @@ -<!DOCTYPE html> -<html> -<!-- -Copyright 2008 The Closure Library Authors. All Rights Reserved. - -Use of this source code is governed by the Apache License, Version 2.0. -See the COPYING file for details. ---> -<!-- ---> -<head> -<meta http-equiv="X-UA-Compatible" content="IE=edge"> - <title>Closure Unit Tests - goog.net.IframeLoadMonitor</title> - <script src="../base.js"></script> - <script> - goog.require('goog.dom'); - goog.require('goog.events'); - goog.require('goog.net.IframeLoadMonitor'); - goog.require('goog.testing.AsyncTestCase'); - goog.require('goog.testing.jsunit'); - </script> -</head> -<body> -<div id="frame_parent"></div> -<script> - var TEST_FRAME_SRCS = ['iframeloadmonitor_test_frame.html', - 'iframeloadmonitor_test_frame2.html', - 'iframeloadmonitor_test_frame3.html']; - - // Create a new test case. - var iframeLoaderTestCase = new goog.testing.AsyncTestCase(document.title); - iframeLoaderTestCase.stepTimeout = 4 * 1000; - - // Array holding all iframe load monitors. - iframeLoaderTestCase.iframeLoadMonitors_ = []; - - // How many single frames finished loading - iframeLoaderTestCase.singleComplete_ = 0; - - /** Sets up the test environment, adds tests and sets up the worker pools. */ - iframeLoaderTestCase.setUpPage = function() { - this.log('Setting tests up'); - iframeLoaderTestCase.waitForAsync('loading iframes'); - - var dom = goog.dom.getDomHelper(); - - // Load single frame - var frame = dom.createDom('iframe'); - this.iframeLoadMonitors_.push(new goog.net.IframeLoadMonitor(frame)); - goog.events.listen(this.iframeLoadMonitors_[0], - goog.net.IframeLoadMonitor.LOAD_EVENT, this); - var frameParent = dom.getElement('frame_parent'); - dom.appendChild(frameParent, frame); - this.log('Loading frame at: ' + TEST_FRAME_SRCS[0]); - frame.src = TEST_FRAME_SRCS[0]; - - // Load single frame with content check - var frame1 = dom.createDom('iframe'); - this.iframeLoadMonitors_.push(new goog.net.IframeLoadMonitor(frame1, true)); - goog.events.listen(this.iframeLoadMonitors_[1], - goog.net.IframeLoadMonitor.LOAD_EVENT, this); - var frameParent = dom.getElement('frame_parent'); - dom.appendChild(frameParent, frame1); - this.log('Loading frame with content check at: ' + TEST_FRAME_SRCS[0]); - frame1.src = TEST_FRAME_SRCS[0]; - - this.add(new goog.testing.TestCase.Test( - 'test results', this.testResults, this)); - }; - - - /** Handles any events fired */ - iframeLoaderTestCase.handleEvent = function(e) { - this.log('handleEvent, type: ' + e.type); - if (e.type == goog.net.IframeLoadMonitor.LOAD_EVENT) { - this.singleComplete_++; - this.callbacksComplete(); - } - }; - - /** Checks if all the load callbacks are done*/ - iframeLoaderTestCase.callbacksComplete = function() { - if (this.singleComplete_ == 2) { - iframeLoaderTestCase.continueTesting(); - } - } - - /** Tests the results. */ - iframeLoaderTestCase.testResults = function() { - this.log('getting test results'); - for (var i = 0; i < this.iframeLoadMonitors_.length; i++) { - assertTrue(this.iframeLoadMonitors_[i].isLoaded()); - } - }; - - /** Used by the JsUnit test runner. */ - function testResults() { - iframeLoaderTestCase.testResults(); - } - - /** Used by the JsUnit test runner. */ - function setUpPage() { - iframeLoaderTestCase.runTests(); - } - - /** Standalone Closure Test Runner. */ - if (typeof G_testRunner != 'undefined') { - G_testRunner.initialize(iframeLoaderTestCase); - } - -</script> -</body> -</html> diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/iframeloadmonitor_test_frame.html.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/iframeloadmonitor_test_frame.html.svn-base deleted file mode 100644 index 9fbcbfa..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/iframeloadmonitor_test_frame.html.svn-base +++ /dev/null @@ -1,12 +0,0 @@ -<html> -<!-- -Copyright 2010 The Closure Library Authors. All Rights Reserved. - -Use of this source code is governed by the Apache License, Version 2.0. -See the COPYING file for details. ---> -<head><title>Iframe Load Test Frame 1</title></head> -<body> - Iframe Load Test Frame 1 -</body> -</html> diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/iframeloadmonitor_test_frame2.html.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/iframeloadmonitor_test_frame2.html.svn-base deleted file mode 100644 index 7d436e2..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/iframeloadmonitor_test_frame2.html.svn-base +++ /dev/null @@ -1,12 +0,0 @@ -<html> -<!-- -Copyright 2010 The Closure Library Authors. All Rights Reserved. - -Use of this source code is governed by the Apache License, Version 2.0. -See the COPYING file for details. ---> -<head><title>Iframe Load Test Frame 2</title></head> -<body> - Iframe Load Test Frame 2 -</body> -</html> diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/iframeloadmonitor_test_frame3.html.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/iframeloadmonitor_test_frame3.html.svn-base deleted file mode 100644 index 910b639..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/iframeloadmonitor_test_frame3.html.svn-base +++ /dev/null @@ -1,12 +0,0 @@ -<html> -<!-- -Copyright 2010 The Closure Library Authors. All Rights Reserved. - -Use of this source code is governed by the Apache License, Version 2.0. -See the COPYING file for details. ---> -<head><title>Iframe Load Test Frame 3</title></head> -<body> - Iframe Load Test Frame 3 -</body> -</html> diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/imageloader.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/imageloader.js.svn-base deleted file mode 100644 index cbe4467..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/imageloader.js.svn-base +++ /dev/null @@ -1,237 +0,0 @@ -// Copyright 2008 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Image loader utility class. Useful when an application needs - * to preload multiple images, for example so they can be sized. - * - * @author attila@google.com (Attila Bodis) - * @author zachlloyd@google.com (Zachary Lloyd) - */ - -goog.provide('goog.net.ImageLoader'); - -goog.require('goog.dom'); -goog.require('goog.events.EventHandler'); -goog.require('goog.events.EventTarget'); -goog.require('goog.events.EventType'); -goog.require('goog.net.EventType'); -goog.require('goog.object'); -goog.require('goog.userAgent'); - - - -/** - * Image loader utility class. Raises a {@link goog.events.EventType.LOAD} - * event for each image loaded, with an {@link Image} object as the target of - * the event, normalized to have {@code naturalHeight} and {@code naturalWidth} - * attributes. - * @param {Element=} opt_parent An optional parent element whose document object - * should be used to load images. - * @constructor - * @extends {goog.events.EventTarget} - */ -goog.net.ImageLoader = function(opt_parent) { - goog.events.EventTarget.call(this); - this.images_ = {}; - this.handler_ = new goog.events.EventHandler(this); - this.parent_ = opt_parent; -}; -goog.inherits(goog.net.ImageLoader, goog.events.EventTarget); - - -/** - * Map of image IDs to images src, used to keep track of the images to load. - * @private - * @type {Object.<string, string>} - */ -goog.net.ImageLoader.prototype.images_; - - -/** - * Event handler object, used to keep track of onload and onreadystatechange - * listeners. - * @private - * @type {goog.events.EventHandler} - */ -goog.net.ImageLoader.prototype.handler_; - - -/** - * The parent element whose document object will be used to load images. - * Useful if you want to load the images from a window other than the current - * window in order to control the Referer header sent when the image is loaded. - * @type {(Element|undefined)} - * @private - */ -goog.net.ImageLoader.prototype.parent_; - - -/** - * Adds an image to the image loader, and associates it with the given ID - * string. If an image with that ID already exists, it is silently replaced. - * When the image in question is loaded, the target of the LOAD event will be - * an {@code Image} object with {@code id} and {@code src} attributes based on - * these arguments. - * @param {string} id The ID of the image to load. - * @param {string|Image} image Either the source URL of the image or the HTML - * image element itself (or any object with a {@code src} property, really). - */ -goog.net.ImageLoader.prototype.addImage = function(id, image) { - var src = goog.isString(image) ? image : image.src; - if (src) { - // For now, we just store the source URL for the image. - this.images_[id] = src; - } -}; - - -/** - * Removes the image associated with the given ID string from the image loader. - * @param {string} id The ID of the image to remove. - */ -goog.net.ImageLoader.prototype.removeImage = function(id) { - goog.object.remove(this.images_, id); -}; - - -/** - * Starts loading all images in the image loader in parallel. Raises a LOAD - * event each time an image finishes loading, and a COMPLETE event after all - * images have finished loading. - */ -goog.net.ImageLoader.prototype.start = function() { - goog.object.forEach(this.images_, this.loadImage_, this); -}; - - -/** - * Creates an {@code Image} object with the specified ID and source URL, and - * listens for network events raised as the image is loaded. - * @private - * @param {string} src The image source URL. - * @param {string} id The unique ID of the image to load. - */ -goog.net.ImageLoader.prototype.loadImage_ = function(src, id) { - var image; - if (this.parent_) { - var dom = goog.dom.getDomHelper(this.parent_); - image = dom.createDom('img'); - } else { - image = new Image(); - } - - // Internet Explorer doesn't reliably raise LOAD events on images, so we must - // use READY_STATE_CHANGE (thanks, Jeff!). - // If the image is cached locally, IE won't fire the LOAD event while the - // onreadystate event is fired always. On the other hand, the ERROR event - // is always fired whenever the image is not loaded successfully no matter - // whether it's cached or not. - - var loadEvent = goog.userAgent.IE ? goog.net.EventType.READY_STATE_CHANGE : - goog.events.EventType.LOAD; - this.handler_.listen(image, [ - loadEvent, goog.net.EventType.ABORT, goog.net.EventType.ERROR - ], this.onNetworkEvent_); - - image.id = id; - image.src = src; -}; - - -/** - * Handles net events (READY_STATE_CHANGE, LOAD, ABORT, and ERROR). - * @private - * @param {goog.events.Event} evt The network event to handle. - */ -goog.net.ImageLoader.prototype.onNetworkEvent_ = function(evt) { - var image = evt.currentTarget; - - if (!image) { - return; - } - - if (evt.type == goog.net.EventType.READY_STATE_CHANGE) { - // This implies that the user agent is IE; see loadImage()_. - // Noe that this block is used to check whether the image is ready to - // dispatch the COMPLETE event. - if (image.readyState == goog.net.EventType.COMPLETE) { - // This is the IE equivalent of a LOAD event. - evt.type = goog.events.EventType.LOAD; - } else { - // This may imply that the load failed. - // Note that the image has only the following states: - // * uninitialized - // * loading - // * complete - // When the ERROR or the ABORT event is fired, the readyState - // will be either uninitialized or loading and we'd ignore those states - // since they will be handled separately (eg: evt.type = 'ERROR'). - - // Notes from MSDN : The states through which an object passes are - // determined by that object. An object can skip certain states - // (for example, interactive) if the state does not apply to that object. - // see http://msdn.microsoft.com/en-us/library/ms534359(VS.85).aspx - - // The image is not loaded, ignore. - return; - } - } - - // Add natural width/height properties for non-Gecko browsers. - if (typeof image.naturalWidth == 'undefined') { - if (evt.type == goog.events.EventType.LOAD) { - image.naturalWidth = image.width; - image.naturalHeight = image.height; - } else { - // This implies that the image fails to be loaded. - image.naturalWidth = 0; - image.naturalHeight = 0; - } - } - - // Redispatch the event on behalf of the image. Note that the external - // listener may dispose this instance. - this.dispatchEvent({type: evt.type, target: image}); - - if (this.isDisposed()) { - // If instance was disposed by listener, exit this function. - return; - } - - // Remove the image from the map. - goog.object.remove(this.images_, image.id); - - // If this was the last image, raise a COMPLETE event. - if (goog.object.isEmpty(this.images_)) { - this.dispatchEvent(goog.net.EventType.COMPLETE); - // Unlisten for all network events. - if (this.handler_) { - this.handler_.removeAll(); - } - } -}; - - -/** @override */ -goog.net.ImageLoader.prototype.disposeInternal = function() { - if (this.images_) { - delete this.images_; - } - if (this.handler_) { - this.handler_.dispose(); - this.handler_ = null; - } - goog.net.ImageLoader.superClass_.disposeInternal.call(this); -}; diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/imageloader_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/imageloader_test.html.svn-base deleted file mode 100644 index 9d8b3d8..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/imageloader_test.html.svn-base +++ /dev/null @@ -1,200 +0,0 @@ -<!DOCTYPE html> -<html> -<!-- -Copyright 2006 The Closure Library Authors. All Rights Reserved. - -Use of this source code is governed by the Apache License, Version 2.0. -See the COPYING file for details. ---> -<!-- ---> -<head> -<meta http-equiv="X-UA-Compatible" content="IE=edge"> - <title>Closure Unit Tests - goog.net.ImageLoader</title> - <script src="../base.js"></script> - <script> - goog.require('goog.events'); - goog.require('goog.events.EventType'); - goog.require('goog.net.ImageLoader'); - goog.require('goog.structs.Map'); - goog.require('goog.testing.jsunit'); - </script> -</head> -<body> -<script> - - - - var TEST_IMAGES = new goog.structs.Map(); - - var TEST_EVENT_TYPES = [ - goog.events.EventType.LOAD, - goog.net.EventType.COMPLETE, - goog.net.EventType.ERROR - ]; - - // TEST_IMAGES.set(FileName, Expected Size (width, height), Expected event) - var EVENT_TYPE_LOAD = goog.events.EventType.LOAD; - TEST_IMAGES.set('imageloader_testimg1.gif', [20, 20, EVENT_TYPE_LOAD]); - TEST_IMAGES.set('imageloader_testimg2.gif', [20, 20, EVENT_TYPE_LOAD]); - TEST_IMAGES.set('imageloader_testimg3.gif', [32, 32, EVENT_TYPE_LOAD]); - - var EVENT_TYPE_ERROR = goog.net.EventType.ERROR; - TEST_IMAGES.set('this-is-not-image-1.gif', [0, 0, EVENT_TYPE_ERROR]); - TEST_IMAGES.set('this-is-not-image-2.gif', [0, 0, EVENT_TYPE_ERROR]); - - var TIMEOUT = 5000; - // in milleseconds - - // Create a new test case. - var imageLoaderTestCase = new goog.testing.TestCase(document.title); - var setUpPageStatus; - - // Keep track of time so we can timeout if the images don't load. - imageLoaderTestCase.elapsedTime_ = 0; - - imageLoaderTestCase.results_ = new goog.structs.Map(); - - /** True once the test environment is set up. */ - imageLoaderTestCase.isSetUp = false; - - /** True once the page is ready for the test to be run. */ - imageLoaderTestCase.isReady = false; - - // A regular image loader. - imageLoaderTestCase.imageLoader = new goog.net.ImageLoader(); - - // An image loader that is used to check whether we can dispose - // it safely whenever an event is fired before the COMPLETE event. - imageLoaderTestCase.disposalImageLoader = new goog.net.ImageLoader(); - - /** Sets up the test environment, adds tests and sets up the worker pools. */ - imageLoaderTestCase.setUpTests = function() { - this.log('Setting tests up'); - - this.add(new goog.testing.TestCase.Test('testCompleteResults', - this.testCompleteResults, this)); - - this.isSetUp = true; - - var keys = TEST_IMAGES.getKeys(); - for (var i = 0; i < keys.length; i++) { - this.log('Adding image: ' + keys[i]); - this.imageLoader.addImage('img_' + i, keys[i]); - this.disposalImageLoader.addImage('img_' + i, keys[i]); - } - - goog.events.listen(this.imageLoader, TEST_EVENT_TYPES, - this.handleImageLoaderEvent, false, this); - - goog.events.listen(this.disposalImageLoader, TEST_EVENT_TYPES, - this.handleDisposalImageLoaderEvent, false, this); - - this.disposalImageLoader.start(); - }; - - /** Handles any events fired on the disposalImageLoader */ - imageLoaderTestCase.handleDisposalImageLoaderEvent = function(e) { - switch (e.type) { - case goog.events.EventType.LOAD: - case goog.net.EventType.ERROR: - // Make sure that we can dispose this.disposalImageLoader safely. - this.disposalImageLoader.dispose(); - - // then starts the regular image loader. - this.imageLoader.start(); - break; - - case goog.net.EventType.COMPLETE: - throw new Error('disposalImageLoader should have been disposed.'); - break; - } - }; - - - /** Handles any events fired on the imageLoader */ - imageLoaderTestCase.handleImageLoaderEvent = function(e) { - this.log('handleEvent, type: ' + e.type); - - switch (e.type) { - case goog.events.EventType.LOAD: - var image = e.target; - this.results_.set(image.src.substring(image.src.lastIndexOf('/') + 1), - [image.naturalWidth, image.naturalHeight, e.type]); - break; - - case goog.net.EventType.ERROR: - var image = e.target; - this.results_.set(image.src.substring(image.src.lastIndexOf('/') + 1), - [image.naturalWidth, image.naturalHeight, e.type]); - break; - - case goog.net.EventType.COMPLETE: - setUpPageStatus = 'complete'; - this.isReady = true; - break; - } - }; - - - /** Tests the results. */ - imageLoaderTestCase.testCompleteResults = function() { - var keys = TEST_IMAGES.getKeys(); - for (var i = 0; i < keys.length; i++) { - var key = keys[i]; - this.log(key); - - // Check if fires the COMPLETE event. - assertTrue('Image is not loaded completely', - this.results_.containsKey(key)); - - // Chcekc size. - assertTrue('Image size is not correct', - this.results_.get(key)[0] == TEST_IMAGES.get(key)[0] && - this.results_.get(key)[1] == TEST_IMAGES.get(key)[1]); - - // Check if fired the correct event. - assertTrue('Event *' + TEST_IMAGES.get(key)[2] + '* must be fired', - this.results_.get(key)[2] == TEST_IMAGES.get(key)[2]); - } - }; - - /** Waits until the tests are ready to begin, before running them. */ - imageLoaderTestCase.runTests = function() { - if (!this.isSetUp) { - this.setUpTests(); - } - if (this.isReady) { - this.execute(); - } else { - if (this.elapsedTime_ > TIMEOUT) { - this.log('timed out'); - setUpPageStatus = 'complete'; - this.isReady = true; - return; - } - this.log('Not ready, waiting'); - this.elapsedTime_ += 100; - // Try again in 100ms - setTimeout('imageLoaderTestCase.runTests()', 100); - } - }; - - /** Used by the JsUnit test runner. */ - function testCompleteResults() { - imageLoaderTestCase.testCompleteResults(); - } - - /** Used by the JsUnit test runner. */ - function setUpPage() { - imageLoaderTestCase.runTests(); - } - - /** Standalone Closure Test Runner. */ - if (typeof G_testRunner != 'undefined') { - G_testRunner.initialize(imageLoaderTestCase); - } - -</script> -</body> -</html> diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/imageloader_testimg1.gif.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/imageloader_testimg1.gif.svn-base Binary files differdeleted file mode 100644 index 18b295b..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/imageloader_testimg1.gif.svn-base +++ /dev/null diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/imageloader_testimg2.gif.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/imageloader_testimg2.gif.svn-base Binary files differdeleted file mode 100644 index 6916832..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/imageloader_testimg2.gif.svn-base +++ /dev/null diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/imageloader_testimg3.gif.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/imageloader_testimg3.gif.svn-base Binary files differdeleted file mode 100644 index fe5e378..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/imageloader_testimg3.gif.svn-base +++ /dev/null diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/ipaddress.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/ipaddress.js.svn-base deleted file mode 100644 index 43f46b5..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/ipaddress.js.svn-base +++ /dev/null @@ -1,510 +0,0 @@ -// Copyright 2011 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview This file contains classes to handle IPv4 and IPv6 addresses. - * This implementation is mostly based on Google's project: - * http://code.google.com/p/ipaddr-py/. - * - */ - -goog.provide('goog.net.IpAddress'); -goog.provide('goog.net.Ipv4Address'); -goog.provide('goog.net.Ipv6Address'); - -goog.require('goog.array'); -goog.require('goog.math.Integer'); -goog.require('goog.object'); -goog.require('goog.string'); - - - -/** - * Abstract class defining an IP Address. - * - * Please use goog.net.IpAddress static methods or - * goog.net.Ipv4Address/Ipv6Address classes. - * - * @param {!goog.math.Integer} address The Ip Address. - * @param {number} version The version number (4, 6). - * @constructor - */ -goog.net.IpAddress = function(address, version) { - /** - * The IP Address. - * @type {!goog.math.Integer} - * @private - */ - this.ip_ = address; - - /** - * The IP Address version. - * @type {number} - * @private - */ - this.version_ = version; - - /** - * The IPAddress, as string. - * @type {string} - * @private - */ - this.ipStr_ = ''; -}; - - -/** - * @return {number} The IP Address version. - */ -goog.net.IpAddress.prototype.getVersion = function() { - return this.version_; -}; - - -/** - * @param {!goog.net.IpAddress} other The other IP Address. - * @return {boolean} true if the IP Addresses are equal. - */ -goog.net.IpAddress.prototype.equals = function(other) { - return (this.version_ == other.getVersion() && - this.ip_.equals(other.toInteger())); -}; - - -/** - * @return {goog.math.Integer} The IP Address, as an Integer. - */ -goog.net.IpAddress.prototype.toInteger = function() { - return /** @type {goog.math.Integer} */ (goog.object.clone(this.ip_)); -}; - - -/** - * @return {string} The IP Address, as an URI string following RFC 3986. - */ -goog.net.IpAddress.prototype.toUriString = goog.abstractMethod; - - -/** - * @return {string} The IP Address, as a string. - */ -goog.net.IpAddress.prototype.toString = goog.abstractMethod; - - -/** - * Parses an IP Address in a string. - * If the string is malformed, the function will simply return null - * instead of raising an exception. - * - * @param {string} address The IP Address. - * @see {goog.net.Ipv4Address} - * @see {goog.net.Ipv6Address} - * @return {goog.net.IpAddress} The IP Address or null. - */ -goog.net.IpAddress.fromString = function(address) { - try { - if (address.indexOf(':') != -1) { - return new goog.net.Ipv6Address(address); - } - - return new goog.net.Ipv4Address(address); - } catch (e) { - // Both constructors raise exception if the address is malformed (ie. - // invalid). The user of this function should not care about catching - // the exception, espcially if it's used to validate an user input. - return null; - } -}; - - -/** - * Tries to parse a string represented as a host portion of an URI. - * See RFC 3986 for more details on IPv6 addresses inside URI. - * If the string is malformed, the function will simply return null - * instead of raising an exception. - * - * @param {string} address A RFC 3986 encoded IP address. - * @see {goog.net.Ipv4Address} - * @see {goog.net.Ipv6Address} - * @return {goog.net.IpAddress} The IP Address. - */ -goog.net.IpAddress.fromUriString = function(address) { - try { - if (goog.string.startsWith(address, '[') && - goog.string.endsWith(address, ']')) { - return new goog.net.Ipv6Address( - address.substring(1, address.length - 1)); - } - - return new goog.net.Ipv4Address(address); - } catch (e) { - // Both constructors raise exception if the address is malformed (ie. - // invalid). The user of this function should not care about catching - // the exception, espcially if it's used to validate an user input. - return null; - } -}; - - - -/** - * Takes a string or a number and returns a IPv4 Address. - * - * This constructor accepts strings and instance of goog.math.Integer. - * If you pass a goog.math.Integer, make sure that its sign is set to positive. - * @param {(string|!goog.math.Integer)} address The address to store. - * @extends {goog.net.IpAddress} - * @constructor - */ -goog.net.Ipv4Address = function(address) { - var ip = goog.math.Integer.ZERO; - if (address instanceof goog.math.Integer) { - if (address.getSign() != 0 || - address.lessThan(goog.math.Integer.ZERO) || - address.greaterThan(goog.net.Ipv4Address.MAX_ADDRESS_)) { - throw Error('The address does not look like an IPv4.'); - } else { - ip = goog.object.clone(address); - } - } else { - if (!goog.net.Ipv4Address.REGEX_.test(address)) { - throw Error(address + ' does not look like an IPv4 address.'); - } - - var octets = address.split('.'); - if (octets.length != 4) { - throw Error(address + ' does not look like an IPv4 address.'); - } - - for (var i = 0; i < octets.length; i++) { - var parsedOctet = goog.string.toNumber(octets[i]); - if (isNaN(parsedOctet) || - parsedOctet < 0 || parsedOctet > 255 || - (octets[i].length != 1 && goog.string.startsWith(octets[i], '0'))) { - throw Error('In ' + address + ', octet ' + i + ' is not valid'); - } - var intOctet = goog.math.Integer.fromNumber(parsedOctet); - ip = ip.shiftLeft(8).or(intOctet); - } - } - goog.base(this, /** @type {!goog.math.Integer} */ (ip), 4); -}; -goog.inherits(goog.net.Ipv4Address, goog.net.IpAddress); - - -/** - * Regular expression matching all the allowed chars for IPv4. - * @type {RegExp} - * @private - * @const - */ -goog.net.Ipv4Address.REGEX_ = /^[0-9.]*$/; - - -/** - * The Maximum length for a netmask (aka, the number of bits for IPv4). - * @type {number} - * @const - */ -goog.net.Ipv4Address.MAX_NETMASK_LENGTH = 32; - - -/** - * The Maximum address possible for IPv4. - * @type {goog.math.Integer} - * @private - * @const - */ -goog.net.Ipv4Address.MAX_ADDRESS_ = goog.math.Integer.ONE.shiftLeft( - goog.net.Ipv4Address.MAX_NETMASK_LENGTH).subtract(goog.math.Integer.ONE); - - -/** - * @override - */ -goog.net.Ipv4Address.prototype.toString = function() { - if (this.ipStr_) { - return this.ipStr_; - } - - var ip = this.ip_.getBitsUnsigned(0); - var octets = []; - for (var i = 3; i >= 0; i--) { - octets[i] = String((ip & 0xff)); - ip = ip >>> 8; - } - - this.ipStr_ = octets.join('.'); - - return this.ipStr_; -}; - - -/** - * @override - */ -goog.net.Ipv4Address.prototype.toUriString = function() { - return this.toString(); -}; - - - -/** - * Takes a string or a number and returns an IPv6 Address. - * - * This constructor accepts strings and instance of goog.math.Integer. - * If you pass a goog.math.Integer, make sure that its sign is set to positive. - * @param {(string|!goog.math.Integer)} address The address to store. - * @constructor - * @extends {goog.net.IpAddress} - */ -goog.net.Ipv6Address = function(address) { - var ip = goog.math.Integer.ZERO; - if (address instanceof goog.math.Integer) { - if (address.getSign() != 0 || - address.lessThan(goog.math.Integer.ZERO) || - address.greaterThan(goog.net.Ipv6Address.MAX_ADDRESS_)) { - throw Error('The address does not look like a valid IPv6.'); - } else { - ip = goog.object.clone(address); - } - } else { - if (!goog.net.Ipv6Address.REGEX_.test(address)) { - throw Error(address + ' is not a valid IPv6 address.'); - } - - var splitColon = address.split(':'); - if (splitColon[splitColon.length - 1].indexOf('.') != -1) { - var newHextets = goog.net.Ipv6Address.dottedQuadtoHextets_( - splitColon[splitColon.length - 1]); - goog.array.removeAt(splitColon, splitColon.length - 1); - goog.array.extend(splitColon, newHextets); - address = splitColon.join(':'); - } - - var splitDoubleColon = address.split('::'); - if (splitDoubleColon.length > 2 || - (splitDoubleColon.length == 1 && splitColon.length != 8)) { - throw Error(address + ' is not a valid IPv6 address.'); - } - - var ipArr; - if (splitDoubleColon.length > 1) { - ipArr = goog.net.Ipv6Address.explode_(splitDoubleColon); - } else { - ipArr = splitColon; - } - - if (ipArr.length != 8) { - throw Error(address + ' is not a valid IPv6 address'); - } - - for (var i = 0; i < ipArr.length; i++) { - var parsedHextet = goog.math.Integer.fromString(ipArr[i], 16); - if (parsedHextet.lessThan(goog.math.Integer.ZERO) || - parsedHextet.greaterThan(goog.net.Ipv6Address.MAX_HEXTET_VALUE_)) { - throw Error(ipArr[i] + ' in ' + address + ' is not a valid hextet.'); - } - ip = ip.shiftLeft(16).or(parsedHextet); - } - } - goog.base(this, /** @type {!goog.math.Integer} */ (ip), 6); -}; -goog.inherits(goog.net.Ipv6Address, goog.net.IpAddress); - - -/** - * Regular expression matching all allowed chars for an IPv6. - * @type {RegExp} - * @private - * @const - */ -goog.net.Ipv6Address.REGEX_ = /^([a-fA-F0-9]*:){2}[a-fA-F0-9:.]*$/; - - -/** - * The Maximum length for a netmask (aka, the number of bits for IPv6). - * @type {number} - * @const - */ -goog.net.Ipv6Address.MAX_NETMASK_LENGTH = 128; - - -/** - * The maximum value of a hextet. - * @type {goog.math.Integer} - * @private - * @const - */ -goog.net.Ipv6Address.MAX_HEXTET_VALUE_ = goog.math.Integer.fromInt(65535); - - -/** - * The Maximum address possible for IPv6. - * @type {goog.math.Integer} - * @private - * @const - */ -goog.net.Ipv6Address.MAX_ADDRESS_ = goog.math.Integer.ONE.shiftLeft( - goog.net.Ipv6Address.MAX_NETMASK_LENGTH).subtract(goog.math.Integer.ONE); - - -/** - * @override - */ -goog.net.Ipv6Address.prototype.toString = function() { - if (this.ipStr_) { - return this.ipStr_; - } - - var outputArr = []; - for (var i = 3; i >= 0; i--) { - var bits = this.ip_.getBitsUnsigned(i); - var firstHextet = bits >>> 16; - var secondHextet = bits & 0xffff; - outputArr.push(firstHextet.toString(16)); - outputArr.push(secondHextet.toString(16)); - } - - outputArr = goog.net.Ipv6Address.compress_(outputArr); - this.ipStr_ = outputArr.join(':'); - return this.ipStr_; -}; - - -/** - * @override - */ -goog.net.Ipv6Address.prototype.toUriString = function() { - return '[' + this.toString() + ']'; -}; - - -/** - * This method is in charge of expanding/exploding an IPv6 string from its - * compressed form. - * @private - * @param {!Array.<string>} address An IPv6 address split around '::'. - * @return {Array.<string>} The expanded version of the IPv6. - */ -goog.net.Ipv6Address.explode_ = function(address) { - var basePart = address[0].split(':'); - var secondPart = address[1].split(':'); - - if (basePart.length == 1 && basePart[0] == '') { - basePart = []; - } - if (secondPart.length == 1 && secondPart[0] == '') { - secondPart = []; - } - - // Now we fill the gap with 0. - var gap = 8 - (basePart.length + secondPart.length); - - if (gap < 1) { - return []; - } - - goog.array.extend(basePart, goog.array.repeat('0', gap)); - - // Now we merge the basePart + gap + secondPart - goog.array.extend(basePart, secondPart); - - return basePart; -}; - - -/** - * This method is in charge of compressing an expanded IPv6 array of hextets. - * @private - * @param {!Array.<string>} hextets The array of hextet. - * @return {Array.<string>} The compressed version of this array. - */ -goog.net.Ipv6Address.compress_ = function(hextets) { - var bestStart = -1; - var start = -1; - var bestSize = 0; - var size = 0; - for (var i = 0; i < hextets.length; i++) { - if (hextets[i] == '0') { - size++; - if (start == -1) { - start = i; - } - if (size > bestSize) { - bestSize = size; - bestStart = start; - } - } else { - start = -1; - size = 0; - } - } - - if (bestSize > 0) { - if ((bestStart + bestSize) == hextets.length) { - hextets.push(''); - } - hextets.splice(bestStart, bestSize, ''); - - if (bestStart == 0) { - hextets = [''].concat(hextets); - } - } - return hextets; -}; - - -/** - * This method will convert an IPv4 to a list of 2 hextets. - * - * For instance, 1.2.3.4 will be converted to ['0102', '0304']. - * @private - * @param {string} quads An IPv4 as a string. - * @return {Array.<string>} A list of 2 hextets. - */ -goog.net.Ipv6Address.dottedQuadtoHextets_ = function(quads) { - var ip4 = new goog.net.Ipv4Address(quads).toInteger(); - var bits = ip4.getBitsUnsigned(0); - var hextets = []; - - hextets.push(((bits >>> 16) & 0xffff).toString(16)); - hextets.push((bits & 0xffff).toString(16)); - - return hextets; -}; - - -/** - * @return {boolean} true if the IPv6 contains a mapped IPv4. - */ -goog.net.Ipv6Address.prototype.isMappedIpv4Address = function() { - return (this.ip_.getBitsUnsigned(3) == 0 && - this.ip_.getBitsUnsigned(2) == 0 && - this.ip_.getBitsUnsigned(1) == 0xffff); -}; - - -/** - * Will return the mapped IPv4 address in this IPv6 address. - * @return {goog.net.Ipv4Address} an IPv4 or null. - */ -goog.net.Ipv6Address.prototype.getMappedIpv4Address = function() { - if (!this.isMappedIpv4Address()) { - return null; - } - - var newIpv4 = new goog.math.Integer([this.ip_.getBitsUnsigned(0)], 0); - return new goog.net.Ipv4Address(newIpv4); -}; diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/ipaddress_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/ipaddress_test.html.svn-base deleted file mode 100644 index 8ffe01c..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/ipaddress_test.html.svn-base +++ /dev/null @@ -1,227 +0,0 @@ -<!DOCTYPE html> -<html> -<!-- -Copyright 2011 The Closure Library Authors. All Rights Reserved. - -Use of this source code is governed by the Apache License, Version 2.0. -See the COPYING file for details. - -Test suite inspired from http://code.google.com/p/ipaddr-py/ and -Google's Guava InetAddresses test suite available on -http://code.google.com/p/guava-libraries/ ---> - <head> - <meta http-equiv='X-UA-Compatible' content='IE=edge'> - <title>Closure Unit Test - goog.net.IpAddress</title> - <script src='../base.js' type='text/javascript'></script> - <script type='text/javascript'> - goog.require('goog.array'); - goog.require('goog.math.Integer'); - goog.require('goog.net.IpAddress'); - goog.require('goog.net.Ipv4Address'); - goog.require('goog.net.Ipv6Address'); - goog.require('goog.testing.jsunit'); - </script> - </head> - <body> - <script text='text/javascript'> - function testInvalidStrings() { - assertEquals(null, goog.net.IpAddress.fromString('')); - assertEquals(null, goog.net.IpAddress.fromString('016.016.016.016')); - assertEquals(null, goog.net.IpAddress.fromString('016.016.016')); - assertEquals(null, goog.net.IpAddress.fromString('016.016')); - assertEquals(null, goog.net.IpAddress.fromString('016')); - assertEquals(null, goog.net.IpAddress.fromString('000.000.000.000')); - assertEquals(null, goog.net.IpAddress.fromString('000')); - assertEquals(null, - goog.net.IpAddress.fromString('0x0a.0x0a.0x0a.0x0a')); - assertEquals(null, goog.net.IpAddress.fromString('0x0a.0x0a.0x0a')); - assertEquals(null, goog.net.IpAddress.fromString('0x0a.0x0a')); - assertEquals(null, goog.net.IpAddress.fromString('0x0a')); - assertEquals(null, goog.net.IpAddress.fromString('42.42.42.42.42')); - assertEquals(null, goog.net.IpAddress.fromString('42.42.42')); - assertEquals(null, goog.net.IpAddress.fromString('42.42')); - assertEquals(null, goog.net.IpAddress.fromString('42')); - assertEquals(null, goog.net.IpAddress.fromString('42..42.42')); - assertEquals(null, goog.net.IpAddress.fromString('42..42.42.42')); - assertEquals(null, goog.net.IpAddress.fromString('42.42.42.42.')); - assertEquals(null, goog.net.IpAddress.fromString('42.42.42.42...')); - assertEquals(null, goog.net.IpAddress.fromString('.42.42.42.42')); - assertEquals(null, goog.net.IpAddress.fromString('...42.42.42.42')); - assertEquals(null, goog.net.IpAddress.fromString('42.42.42.-0')); - assertEquals(null, goog.net.IpAddress.fromString('42.42.42.+0')); - assertEquals(null, goog.net.IpAddress.fromString('.')); - assertEquals(null, goog.net.IpAddress.fromString('...')); - assertEquals(null, goog.net.IpAddress.fromString('bogus')); - assertEquals(null, goog.net.IpAddress.fromString('bogus.com')); - assertEquals(null, goog.net.IpAddress.fromString('192.168.0.1.com')); - assertEquals(null, - goog.net.IpAddress.fromString('12345.67899.-54321.-98765')); - assertEquals(null, goog.net.IpAddress.fromString('257.0.0.0')); - assertEquals(null, goog.net.IpAddress.fromString('42.42.42.-42')); - assertEquals(null, goog.net.IpAddress.fromString('3ff3:::1')); - assertEquals(null, goog.net.IpAddress.fromString('3ffe::1.net')); - assertEquals(null, goog.net.IpAddress.fromString('3ffe::1::1')); - assertEquals(null, goog.net.IpAddress.fromString('1::2::3::4:5')); - assertEquals(null, goog.net.IpAddress.fromString('::7:6:5:4:3:2:')); - assertEquals(null, goog.net.IpAddress.fromString(':6:5:4:3:2:1::')); - assertEquals(null, goog.net.IpAddress.fromString('2001::db:::1')); - assertEquals(null, goog.net.IpAddress.fromString('FEDC:9878')); - assertEquals(null, goog.net.IpAddress.fromString('+1.+2.+3.4')); - assertEquals(null, goog.net.IpAddress.fromString('1.2.3.4e0')); - assertEquals(null, goog.net.IpAddress.fromString('::7:6:5:4:3:2:1:0')); - assertEquals(null, goog.net.IpAddress.fromString('7:6:5:4:3:2:1:0::')); - assertEquals(null, goog.net.IpAddress.fromString('9:8:7:6:5:4:3::2:1')); - assertEquals(null, goog.net.IpAddress.fromString('0:1:2:3::4:5:6:7')); - assertEquals(null, - goog.net.IpAddress.fromString('3ffe:0:0:0:0:0:0:0:1')); - assertEquals(null, goog.net.IpAddress.fromString('3ffe::10000')); - assertEquals(null, goog.net.IpAddress.fromString('3ffe::goog')); - assertEquals(null, goog.net.IpAddress.fromString('3ffe::-0')); - assertEquals(null, goog.net.IpAddress.fromString('3ffe::+0')); - assertEquals(null, goog.net.IpAddress.fromString('3ffe::-1')); - assertEquals(null, goog.net.IpAddress.fromString(':')); - assertEquals(null, goog.net.IpAddress.fromString(':::')); - assertEquals(null, goog.net.IpAddress.fromString('a:')); - assertEquals(null, goog.net.IpAddress.fromString('::a:')); - assertEquals(null, goog.net.IpAddress.fromString('0xa::')); - assertEquals(null, goog.net.IpAddress.fromString('::1.2.3')); - assertEquals(null, goog.net.IpAddress.fromString('::1.2.3.4.5')); - assertEquals(null, goog.net.IpAddress.fromString('::1.2.3.4:')); - assertEquals(null, goog.net.IpAddress.fromString('1.2.3.4::')); - assertEquals(null, goog.net.IpAddress.fromString('2001:db8::1:')); - assertEquals(null, goog.net.IpAddress.fromString(':2001:db8::1')); - } - - function testVersion() { - var ip4 = goog.net.IpAddress.fromString('1.2.3.4'); - assertEquals(ip4.getVersion(), 4); - - var ip6 = goog.net.IpAddress.fromString('2001:dead::beef:1'); - assertEquals(ip6.getVersion(), 6); - - ip6 = goog.net.IpAddress.fromString('::192.168.1.1'); - assertEquals(ip6.getVersion(), 6); - } - - function testStringIpv4Address() { - assertEquals('192.168.1.1', - new goog.net.Ipv4Address('192.168.1.1').toString()); - assertEquals('1.1.1.1', - new goog.net.Ipv4Address('1.1.1.1').toString()); - assertEquals('224.56.33.2', - new goog.net.Ipv4Address('224.56.33.2').toString()); - assertEquals('255.255.255.255', - new goog.net.Ipv4Address('255.255.255.255').toString()); - assertEquals('0.0.0.0', - new goog.net.Ipv4Address('0.0.0.0').toString()); - } - - function testIntIpv4Address() { - var ip4Str = new goog.net.Ipv4Address('1.1.1.1'); - var ip4Int = new goog.net.Ipv4Address( - new goog.math.Integer([16843009], 0)); - - assertTrue(ip4Str.equals(ip4Int)); - assertEquals(ip4Str.toString(), ip4Int.toString()); - - assertThrows('Ipv4(-1)', goog.partial(goog.net.Ipv4Address, - goog.math.Integer.fromInt(-1))); - assertThrows('Ipv4(2**32)', - goog.partial(goog.net.Ipv4Address, - goog.math.Integer.ONE.shiftLeft(32))); - } - - function testStringIpv6Address() { - assertEquals('1:2:3:4:5:6:7:8', - new goog.net.Ipv6Address('1:2:3:4:5:6:7:8').toString()); - assertEquals('::1:2:3:4:5:6:7', - new goog.net.Ipv6Address('::1:2:3:4:5:6:7').toString()); - assertEquals('1:2:3:4:5:6:7::', - new goog.net.Ipv6Address('1:2:3:4:5:6:7:0').toString()); - assertEquals('2001:0:0:4::8', - new goog.net.Ipv6Address('2001:0:0:4:0:0:0:8').toString()); - assertEquals('2001::4:5:6:7:8', - new goog.net.Ipv6Address('2001:0:0:4:5:6:7:8').toString()); - assertEquals('2001::3:4:5:6:7:8', - new goog.net.Ipv6Address('2001:0:3:4:5:6:7:8').toString()); - assertEquals('0:0:3::ffff', - new goog.net.Ipv6Address('0:0:3:0:0:0:0:ffff').toString()); - assertEquals('::4:0:0:0:ffff', - new goog.net.Ipv6Address('0:0:0:4:0:0:0:ffff').toString()); - assertEquals('::5:0:0:ffff', - new goog.net.Ipv6Address('0:0:0:0:5:0:0:ffff').toString()); - assertEquals('1::4:0:0:7:8', - new goog.net.Ipv6Address('1:0:0:4:0:0:7:8').toString()); - assertEquals('::', - new goog.net.Ipv6Address('0:0:0:0:0:0:0:0').toString()); - assertEquals('::1', - new goog.net.Ipv6Address('0:0:0:0:0:0:0:1').toString()); - assertEquals('2001:658:22a:cafe::', - new goog.net.Ipv6Address( - '2001:0658:022a:cafe:0000:0000:0000:0000').toString()); - assertEquals('::102:304', - new goog.net.Ipv6Address('::1.2.3.4').toString()); - assertEquals('::ffff:303:303', - new goog.net.Ipv6Address('::ffff:3.3.3.3').toString()); - assertEquals('::ffff:ffff', - new goog.net.Ipv6Address('::255.255.255.255').toString()); - } - - function testIntIpv6Address() { - var ip6Str = new goog.net.Ipv6Address('2001::dead:beef:1'); - var ip6Int = new goog.net.Ipv6Address( - new goog.math.Integer([3203334145, 57005, 0, 536936448], 0)); - - assertTrue(ip6Str.equals(ip6Int)); - assertEquals(ip6Str.toString(), ip6Int.toString()); - - assertThrows('Ipv6(-1)', goog.partial(goog.net.Ipv6Address, - goog.math.Integer.fromInt(-1))); - assertThrows('Ipv6(2**128)', - goog.partial(goog.net.Ipv6Address, - goog.math.Integer.ONE.shiftLeft(128))); - - } - - function testDottedQuadIpv6() { - var ip6 = new goog.net.Ipv6Address('7::0.128.0.127'); - ip6 = new goog.net.Ipv6Address('7::0.128.0.128'); - ip6 = new goog.net.Ipv6Address('7::128.128.0.127'); - ip6 = new goog.net.Ipv6Address('7::0.128.128.127'); - } - - function testMappedIpv4Address() { - var testAddresses = ['::ffff:1.2.3.4', '::FFFF:102:304']; - var ipv4Str = '1.2.3.4'; - - var ip1 = new goog.net.Ipv6Address(testAddresses[0]); - var ip2 = new goog.net.Ipv6Address(testAddresses[1]); - var ipv4 = new goog.net.Ipv4Address(ipv4Str); - - assertTrue(ip1.isMappedIpv4Address()); - assertTrue(ip2.isMappedIpv4Address()); - assertTrue(ip1.equals(ip2)); - assertTrue(ipv4.equals(ip1.getMappedIpv4Address())); - assertTrue(ipv4.equals(ip2.getMappedIpv4Address())); - } - - - function testUriString() { - var ip4Str = '192.168.1.1'; - var ip4Uri = goog.net.IpAddress.fromUriString(ip4Str); - var ip4 = goog.net.IpAddress.fromString(ip4Str); - assertTrue(ip4Uri.equals(ip4)); - - var ip6Str = '2001:dead::beef:1'; - assertEquals(null, goog.net.IpAddress.fromUriString(ip6Str)); - - var ip6Uri = goog.net.IpAddress.fromUriString('[' + ip6Str + ']'); - var ip6 = goog.net.IpAddress.fromString(ip6Str); - assertTrue(ip6Uri.equals(ip6)); - assertEquals(ip6Uri.toString(), ip6Str); - assertEquals(ip6Uri.toUriString(), '[' + ip6Str + ']'); - } - </script> - </body> -</html> diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/jsloader.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/jsloader.js.svn-base deleted file mode 100644 index 653b205..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/jsloader.js.svn-base +++ /dev/null @@ -1,362 +0,0 @@ -// Copyright 2011 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview A utility to load JavaScript files. - * Refactored from goog.net.Jsonp. - * - */ - -goog.provide('goog.net.jsloader'); -goog.provide('goog.net.jsloader.Error'); - -goog.require('goog.array'); -goog.require('goog.async.Deferred'); -goog.require('goog.debug.Error'); -goog.require('goog.dom'); -goog.require('goog.userAgent'); - - -/** - * The name of the property of goog.global under which the JavaScript - * verification object is stored by the loaded script. - * @type {string} - * @private - */ -goog.net.jsloader.GLOBAL_VERIFY_OBJS_ = 'closure_verification'; - - -/** - * The default length of time, in milliseconds, we are prepared to wait for a - * load request to complete. - * @type {number} - */ -goog.net.jsloader.DEFAULT_TIMEOUT = 5000; - - -/** - * Optional parameters for goog.net.jsloader.send. - * timeout: The length of time, in milliseconds, we are prepared to wait - * for a load request to complete. Default it 5 seconds. - * document: The HTML document under which to load the JavaScript. Default is - * the current document. - * cleanupWhenDone: If true clean up the script tag after script completes to - * load. This is important if you just want to read data from the JavaScript - * and then throw it away. Default is false. - * - * @typedef {{ - * timeout: (number|undefined), - * document: (HTMLDocument|undefined), - * cleanupWhenDone: (boolean|undefined) - * }} - */ -goog.net.jsloader.Options; - - -/** - * Scripts (URIs) waiting to be loaded. - * @type {Array.<string>} - * @private - */ -goog.net.jsloader.scriptsToLoad_ = []; - - -/** - * Loads and evaluates the JavaScript files at the specified URIs, in order. - * - * @param {Array.<string>} uris The URIs to load. - * @param {goog.net.jsloader.Options=} opt_options Optional parameters. See - * goog.net.jsloader.options documentation for details. - */ -goog.net.jsloader.loadMany = function(uris, opt_options) { - // Loading the scripts in serial introduces asynchronosity into the flow. - // Therefore, there are race conditions where client A can kick off the load - // sequence for client B, even though client A's scripts haven't all been - // loaded yet. - // - // To work around this issue, all module loads share a queue. - if (!uris.length) { - return; - } - - if (goog.userAgent.GECKO && !goog.userAgent.isVersion(2)) { - // For <script> tags that are loaded in this manner, Gecko 1.9 and earlier - // ensures that tag order is consistent with evaluation order. - // Unfortunately, other browsers do not make that guarantee. So the other - // browsers need a slower and more complex implementation. - for (var i = 0; i < uris.length; i++) { - goog.net.jsloader.load(uris[i], opt_options); - } - } else { - var isAnotherModuleLoading = goog.net.jsloader.scriptsToLoad_.length; - goog.array.extend(goog.net.jsloader.scriptsToLoad_, uris); - if (isAnotherModuleLoading) { - // jsloader is still loading some other scripts. - // In order to prevent the race condition noted above, we just add - // these URIs to the end of the scripts' queue and return. - return; - } - - uris = goog.net.jsloader.scriptsToLoad_; - var popAndLoadNextScript = function() { - var uri = uris.shift(); - var deferred = goog.net.jsloader.load(uri, opt_options); - if (uris.length) { - deferred.addBoth(popAndLoadNextScript); - } - }; - popAndLoadNextScript(); - } -}; - - -/** - * Loads and evaluates a JavaScript file. - * When the script loads, a user callback is called. - * It is the client's responsibility to verify that the script ran successfully. - * - * @param {string} uri The URI of the JavaScript. - * @param {goog.net.jsloader.Options=} opt_options Optional parameters. See - * goog.net.jsloader.Options documentation for details. - * @return {!goog.async.Deferred} The deferred result, that may be used to add - * callbacks and/or cancel the transmission. - * The error callback will be called with a single goog.net.jsloader.Error - * parameter. - */ -goog.net.jsloader.load = function(uri, opt_options) { - var options = opt_options || {}; - var doc = options.document || document; - - var script = goog.dom.createElement(goog.dom.TagName.SCRIPT); - var request = {script_: script, timeout_: undefined}; - var deferred = new goog.async.Deferred(goog.net.jsloader.cancel_, request); - - // Set a timeout. - var timeout = null; - var timeoutDuration = goog.isDefAndNotNull(options.timeout) ? - options.timeout : goog.net.jsloader.DEFAULT_TIMEOUT; - if (timeoutDuration > 0) { - timeout = window.setTimeout(function() { - goog.net.jsloader.cleanup_(script, true); - deferred.errback(new goog.net.jsloader.Error( - goog.net.jsloader.ErrorCode.TIMEOUT, - 'Timeout reached for loading script ' + uri)); - }, timeoutDuration); - request.timeout_ = timeout; - } - - // Hang the user callback to be called when the script completes to load. - // NOTE(user): This callback will be called in IE even upon error. In any - // case it is the client's responsibility to verify that the script ran - // successfully. - script.onload = script.onreadystatechange = function() { - if (!script.readyState || script.readyState == 'loaded' || - script.readyState == 'complete') { - var removeScriptNode = options.cleanupWhenDone || false; - goog.net.jsloader.cleanup_(script, removeScriptNode, timeout); - deferred.callback(null); - } - }; - - // Add an error callback. - // NOTE(user): Not supported in IE. - script.onerror = function() { - goog.net.jsloader.cleanup_(script, true, timeout); - deferred.errback(new goog.net.jsloader.Error( - goog.net.jsloader.ErrorCode.LOAD_ERROR, - 'Error while loading script ' + uri)); - }; - - // Add the script element to the document. - goog.dom.setProperties(script, { - 'type': 'text/javascript', - 'charset': 'UTF-8', - // NOTE(user): Safari never loads the script if we don't set - // the src attribute before appending. - 'src': uri - }); - var scriptParent = goog.net.jsloader.getScriptParentElement_(doc); - scriptParent.appendChild(script); - - return deferred; -}; - - -/** - * Loads a JavaScript file and verifies it was evaluated successfully, using a - * verification object. - * The verification object is set by the loaded JavaScript at the end of the - * script. - * We verify this object was set and return its value in the success callback. - * If the object is not defined we trigger an error callback. - * - * @param {string} uri The URI of the JavaScript. - * @param {string} verificationObjName The name of the verification object that - * the loaded script should set. - * @param {goog.net.jsloader.Options} options Optional parameters. See - * goog.net.jsloader.Options documentation for details. - * @return {!goog.async.Deferred} The deferred result, that may be used to add - * callbacks and/or cancel the transmission. - * The success callback will be called with a single parameter containing - * the value of the verification object. - * The error callback will be called with a single goog.net.jsloader.Error - * parameter. - */ -goog.net.jsloader.loadAndVerify = function(uri, verificationObjName, options) { - // Define the global objects variable. - if (!goog.global[goog.net.jsloader.GLOBAL_VERIFY_OBJS_]) { - goog.global[goog.net.jsloader.GLOBAL_VERIFY_OBJS_] = {}; - } - var verifyObjs = goog.global[goog.net.jsloader.GLOBAL_VERIFY_OBJS_]; - - // Verify that the expected object does not exist yet. - if (goog.isDef(verifyObjs[verificationObjName])) { - // TODO(user): Error or reset variable? - return goog.async.Deferred.fail(new goog.net.jsloader.Error( - goog.net.jsloader.ErrorCode.VERIFY_OBJECT_ALREADY_EXISTS, - 'Verification object ' + verificationObjName + ' already defined.')); - } - - // Send request to load the JavaScript. - var sendDeferred = goog.net.jsloader.load(uri, options); - - // Create a deferred object wrapping the send result. - var deferred = new goog.async.Deferred(sendDeferred.cancel); - - // Call user back with object that was set by the script. - sendDeferred.addCallback(function() { - var result = verifyObjs[verificationObjName]; - if (goog.isDef(result)) { - deferred.callback(result); - delete verifyObjs[verificationObjName]; - } else { - // Error: script was not loaded properly. - deferred.errback(new goog.net.jsloader.Error( - goog.net.jsloader.ErrorCode.VERIFY_ERROR, - 'Script ' + uri + ' loaded, but verification object ' + - verificationObjName + ' was not defined.')); - } - }); - - // Pass error to new deferred object. - sendDeferred.addErrback(function(error) { - if (goog.isDef(verifyObjs[verificationObjName])) { - delete verifyObjs[verificationObjName]; - } - deferred.errback(error); - }); - - return deferred; -}; - - -/** - * Gets the DOM element under which we should add new script elements. - * How? Take the first head element, and if not found take doc.documentElement, - * which always exists. - * - * @param {!HTMLDocument} doc The relevant document. - * @return {!Element} The script parent element. - * @private - */ -goog.net.jsloader.getScriptParentElement_ = function(doc) { - var headElements = doc.getElementsByTagName(goog.dom.TagName.HEAD); - if (!headElements || goog.array.isEmpty(headElements)) { - return doc.documentElement; - } else { - return headElements[0]; - } -}; - - -/** - * Cancels a given request. - * @this {{script_: Element, timeout_: number}} The request context. - * @private - */ -goog.net.jsloader.cancel_ = function() { - var request = this; - if (request && request.script_) { - var scriptNode = request.script_; - if (scriptNode && scriptNode.tagName == 'SCRIPT') { - goog.net.jsloader.cleanup_(scriptNode, true, request.timeout_); - } - } -}; - - -/** - * Removes the script node and the timeout. - * - * @param {Node} scriptNode The node to be cleaned up. - * @param {boolean} removeScriptNode If true completely remove the script node. - * @param {?number=} opt_timeout The timeout handler to cleanup. - * @private - */ -goog.net.jsloader.cleanup_ = function(scriptNode, removeScriptNode, - opt_timeout) { - if (goog.isDefAndNotNull(opt_timeout)) { - goog.global.clearTimeout(opt_timeout); - } - - scriptNode.onload = goog.nullFunction; - scriptNode.onerror = goog.nullFunction; - scriptNode.onreadystatechange = goog.nullFunction; - - // Do this after a delay (removing the script node of a running script can - // confuse older IEs). - if (removeScriptNode) { - window.setTimeout(function() { - goog.dom.removeNode(scriptNode); - }, 0); - } -}; - - -/** - * Possible error codes for jsloader. - * @enum {number} - */ -goog.net.jsloader.ErrorCode = { - LOAD_ERROR: 0, - TIMEOUT: 1, - VERIFY_ERROR: 2, - VERIFY_OBJECT_ALREADY_EXISTS: 3 -}; - - - -/** - * A jsloader error. - * - * @param {goog.net.jsloader.ErrorCode} code The error code. - * @param {string=} opt_message Additional message. - * @constructor - * @extends {goog.debug.Error} - */ -goog.net.jsloader.Error = function(code, opt_message) { - var msg = 'Jsloader error (code #' + code + ')'; - if (opt_message) { - msg += ': ' + opt_message; - } - goog.base(this, msg); - - /** - * The code for this error. - * - * @type {goog.net.jsloader.ErrorCode} - */ - this.code = code; -}; -goog.inherits(goog.net.jsloader.Error, goog.debug.Error); diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/jsloader_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/jsloader_test.html.svn-base deleted file mode 100644 index 0436abe..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/jsloader_test.html.svn-base +++ /dev/null @@ -1,134 +0,0 @@ -<!DOCTYPE html> -<html> -<!-- -Copyright 2011 The Closure Library Authors. All Rights Reserved. - -Use of this source code is governed by the Apache License, Version 2.0. -See the COPYING file for details. ---> -<!-- ---> -<head> -<meta http-equiv="X-UA-Compatible" content="IE=edge"> -<title>Closure Unit Tests - goog.net.jsloader</title> -<script src="../base.js"></script> -<script> - goog.require('goog.async.Deferred'); - goog.require('goog.dom'); - goog.require('goog.net.jsloader'); - goog.require('goog.testing.AsyncTestCase'); - goog.require('goog.testing.jsunit'); -</script> -</head> -<body> -<script> - -// Initialize the AsyncTestCase. -var testCase = goog.testing.AsyncTestCase.createAndInstall(document.title); -testCase.stepTimeout = 5 * 1000; // 5 seconds - - -testCase.setUp = function() { - goog.provide = goog.nullFunction; -} - - -testCase.tearDown = function() { - // Remove all the fake scripts. - var scripts = goog.array.clone( - document.getElementsByTagName('SCRIPT')); - for (var i = 0; i < scripts.length; i++) { - if (scripts[i].src.indexOf('testdata') != -1) { - goog.dom.removeNode(scripts[i]); - } - } -} - - -// Sunny day scenario for load function. -function testLoad() { - testCase.waitForAsync('testLoad'); - - window.test1 = null; - var testUrl = 'testdata/jsloader_test1.js'; - var result = goog.net.jsloader.load(testUrl); - result.addCallback(function() { - testCase.continueTesting(); - - var script = result.defaultScope_.script_; - - assertNotNull('script created', script); - assertEquals('encoding is utf-8', 'UTF-8', script.charset); - - // Check that the URI matches ours. - assertTrue('server URI', script.src.indexOf(testUrl) >= 0); - - // Check that the script was really loaded. - assertEquals('verification object', 'Test #1 loaded', window.test1); - }); -} - - -// Sunny day scenario for loadAndVerify function. -function testLoadAndVerify() { - testCase.waitForAsync('testLoadAndVerify'); - - var testUrl = 'testdata/jsloader_test2.js'; - var result = goog.net.jsloader.loadAndVerify(testUrl, 'test2'); - result.addCallback(function(verifyObj) { - testCase.continueTesting(); - - // Check that the verification object has passed ok. - assertEquals('verification object', 'Test #2 loaded', verifyObj); - }); -} - - -// What happens when the verification object is not set by the loaded script? -function testLoadAndVerifyError() { - testCase.waitForAsync('testLoadAndVerifyError'); - - var testUrl = 'testdata/jsloader_test2.js'; - var result = goog.net.jsloader.loadAndVerify(testUrl, 'fake'); - result.addErrback(function(error) { - testCase.continueTesting(); - - // Check that the error code is right. - assertEquals('verification error', goog.net.jsloader.ErrorCode.VERIFY_ERROR, - error.code); - }); -} - - -// Test the loadMany function. -function testLoadMany() { - testCase.waitForAsync('testLoadMany'); - - // Load test #3 and then #1. - window.test1 = null; - var testUrls1 = ['testdata/jsloader_test3.js', 'testdata/jsloader_test1.js']; - goog.net.jsloader.loadMany(testUrls1); - - window.test3Callback = function(msg) { - testCase.continueTesting(); - - // Check that the 1st test was not loaded yet. - assertEquals('verification object', null, window.test1); - - // Load test #4, which is supposed to wait for #1 to load. - testCase.waitForAsync('testLoadMany'); - var testUrls2 = ['testdata/jsloader_test4.js']; - goog.net.jsloader.loadMany(testUrls2); - }; - - window.test4Callback = function(msg) { - testCase.continueTesting(); - - // Check that the 1st test was already loaded. - assertEquals('verification object', 'Test #1 loaded', window.test1); - }; -} - -</script> -</body> -</html> diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/jsonp.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/jsonp.js.svn-base deleted file mode 100644 index 5276a70..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/jsonp.js.svn-base +++ /dev/null @@ -1,341 +0,0 @@ -// Copyright 2006 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// The original file lives here: http://go/cross_domain_channel.js - -/** - * @fileoverview Implements a cross-domain communication channel. A - * typical web page is prevented by browser security from sending - * request, such as a XMLHttpRequest, to other servers than the ones - * from which it came. The Jsonp class provides a workound, by - * using dynamically generated script tags. Typical usage:. - * - * var jsonp = new goog.net.Jsonp(new goog.Uri('http://my.host.com/servlet')); - * var payload = { 'foo': 1, 'bar': true }; - * jsonp.send(payload, function(reply) { alert(reply) }); - * - * This script works in all browsers that are currently supported by - * the Google Maps API, which is IE 6.0+, Firefox 0.8+, Safari 1.2.4+, - * Netscape 7.1+, Mozilla 1.4+, Opera 8.02+. - * - */ - -goog.provide('goog.net.Jsonp'); - -goog.require('goog.Uri'); -goog.require('goog.dom'); -goog.require('goog.net.jsloader'); - -// WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING -// -// This class allows us (Google) to send data from non-Google and thus -// UNTRUSTED pages to our servers. Under NO CIRCUMSTANCES return -// anything sensitive, such as session or cookie specific data. Return -// only data that you want parties external to Google to have. Also -// NEVER use this method to send data from web pages to untrusted -// servers, or redirects to unknown servers (www.google.com/cache, -// /q=xx&btnl, /url, www.googlepages.com, etc.) -// -// WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING - - - -/** - * Creates a new cross domain channel that sends data to the specified - * host URL. By default, if no reply arrives within 5s, the channel - * assumes the call failed to complete successfully. - * - * @param {goog.Uri|string} uri The Uri of the server side code that receives - * data posted through this channel (e.g., - * "http://maps.google.com/maps/geo"). - * - * @param {string=} opt_callbackParamName The parameter name that is used to - * specify the callback. Defaults to "callback". - * - * @constructor - */ -goog.net.Jsonp = function(uri, opt_callbackParamName) { - /** - * The uri_ object will be used to encode the payload that is sent to the - * server. - * @type {goog.Uri} - * @private - */ - this.uri_ = new goog.Uri(uri); - - /** - * This is the callback parameter name that is added to the uri. - * @type {string} - * @private - */ - this.callbackParamName_ = opt_callbackParamName ? - opt_callbackParamName : 'callback'; - - /** - * The length of time, in milliseconds, this channel is prepared - * to wait for for a request to complete. The default value is 5 seconds. - * @type {number} - * @private - */ - this.timeout_ = 5000; -}; - - -/** - * The name of the property of goog.global under which the callback is - * stored. - */ -goog.net.Jsonp.CALLBACKS = '_callbacks_'; - - -/** - * Used to generate unique callback IDs. The counter must be global because - * all channels share a common callback object. - * @private - */ -goog.net.Jsonp.scriptCounter_ = 0; - - -/** - * Sets the length of time, in milliseconds, this channel is prepared - * to wait for for a request to complete. If the call is not competed - * within the set time span, it is assumed to have failed. To wait - * indefinitely for a request to complete set the timout to a negative - * number. - * - * @param {number} timeout The length of time before calls are - * interrupted. - */ -goog.net.Jsonp.prototype.setRequestTimeout = function(timeout) { - this.timeout_ = timeout; -}; - - -/** - * Returns the current timeout value, in milliseconds. - * - * @return {number} The timeout value. - */ -goog.net.Jsonp.prototype.getRequestTimeout = function() { - return this.timeout_; -}; - - -/** - * Sends the given payload to the URL specified at the construction - * time. The reply is delivered to the given replyCallback. If the - * errorCallback is specified and the reply does not arrive within the - * timeout period set on this channel, the errorCallback is invoked - * with the original payload. - * - * If no reply callback is specified, then the response is expected to - * consist of calls to globally registered functions. No &callback= - * URL parameter will be sent in the request, and the script element - * will be cleaned up after the timeout. - * - * @param {Object=} opt_payload Name-value pairs. If given, these will be - * added as parameters to the supplied URI as GET parameters to the - * given server URI. - * - * @param {Function=} opt_replyCallback A function expecting one - * argument, called when the reply arrives, with the response data. - * - * @param {Function=} opt_errorCallback A function expecting one - * argument, called on timeout, with the payload (if given), otherwise - * null. - * - * @param {string=} opt_callbackParamValue Value to be used as the - * parameter value for the callback parameter (callbackParamName). - * To be used when the value needs to be fixed by the client for a - * particular request, to make use of the cached responses for the request. - * NOTE: If multiple requests are made with the same - * opt_callbackParamValue, only the last call will work whenever the - * response comes back. - * - * @return {Object} A request descriptor that may be used to cancel this - * transmission, or null, if the message may not be cancelled. - */ -goog.net.Jsonp.prototype.send = function(opt_payload, - opt_replyCallback, - opt_errorCallback, - opt_callbackParamValue) { - - var payload = opt_payload || null; - - var id = opt_callbackParamValue || - '_' + (goog.net.Jsonp.scriptCounter_++).toString(36) + - goog.now().toString(36); - - if (!goog.global[goog.net.Jsonp.CALLBACKS]) { - goog.global[goog.net.Jsonp.CALLBACKS] = {}; - } - - var script = goog.dom.createElement('script'); - - // Create a new Uri object onto which this payload will be added - var uri = this.uri_.clone(); - if (payload) { - goog.net.Jsonp.addPayloadToUri_(payload, uri); - } - - if (opt_replyCallback) { - var reply = goog.net.Jsonp.newReplyHandler_(id, opt_replyCallback); - goog.global[goog.net.Jsonp.CALLBACKS][id] = reply; - - uri.setParameterValues(this.callbackParamName_, - goog.net.Jsonp.CALLBACKS + '.' + id); - } - - var deferred = goog.net.jsloader.load(uri.toString(), - {timeout: this.timeout_, cleanupWhenDone: true}); - var error = goog.net.Jsonp.newErrorHandler_(id, payload, opt_errorCallback); - deferred.addErrback(error); - - return {id_: id, deferred_: deferred}; -}; - - -/** - * Cancels a given request. The request must be exactly the object returned by - * the send method. - * - * @param {Object} request The request object returned by the send method. - */ -goog.net.Jsonp.prototype.cancel = function(request) { - if (request) { - if (request.deferred_) { - request.deferred_.cancel(); - } - if (request.id_) { - goog.net.Jsonp.cleanup_(request.id_, false); - } - } -}; - - -/** - * Creates a timeout callback that calls the given timeoutCallback with the - * original payload. - * - * @param {string} id The id of the script node. - * @param {Object} payload The payload that was sent to the server. - * @param {Function=} opt_errorCallback The function called on timeout. - * @return {!Function} A zero argument function that handles callback duties. - * @private - */ -goog.net.Jsonp.newErrorHandler_ = function(id, - payload, - opt_errorCallback) { - /** - * When we call across domains with a request, this function is the - * timeout handler. Once it's done executing the user-specified - * error-handler, it removes the script node and original function. - */ - return function() { - goog.net.Jsonp.cleanup_(id, false); - if (opt_errorCallback) { - opt_errorCallback(payload); - } - }; -}; - - -/** - * Creates a reply callback that calls the given replyCallback with data - * returned by the server. - * - * @param {string} id The id of the script node. - * @param {Function} replyCallback The function called on reply. - * @return {Function} A reply callback function. - * @private - */ -goog.net.Jsonp.newReplyHandler_ = function(id, replyCallback) { - /** - * This function is the handler for the all-is-well response. It - * clears the error timeout handler, calls the user's handler, then - * removes the script node and itself. - * - * @param {...Object} var_args The response data sent from the server. - */ - return function(var_args) { - goog.net.Jsonp.cleanup_(id, true); - replyCallback.apply(undefined, arguments); - }; -}; - - -/** - * Removes the script node and reply handler with the given id. - * - * @param {string} id The id of the script node to be removed. - * @param {boolean} deleteReplyHandler If true, delete the reply handler - * instead of setting it to nullFunction (if we know the callback could - * never be called again). - * @private - */ -goog.net.Jsonp.cleanup_ = function(id, deleteReplyHandler) { - if (goog.global[goog.net.Jsonp.CALLBACKS][id]) { - if (deleteReplyHandler) { - delete goog.global[goog.net.Jsonp.CALLBACKS][id]; - } else { - // Removing the script tag doesn't necessarily prevent the script - // from firing, so we make the callback a noop. - goog.global[goog.net.Jsonp.CALLBACKS][id] = goog.nullFunction; - } - } -}; - - -/** - * Returns URL encoded payload. The payload should be a map of name-value - * pairs, in the form {"foo": 1, "bar": true, ...}. If the map is empty, - * the URI will be unchanged. - * - * <p>The method uses hasOwnProperty() to assure the properties are on the - * object, not on its prototype. - * - * @param {!Object} payload A map of value name pairs to be encoded. - * A value may be specified as an array, in which case a query parameter - * will be created for each value, e.g.: - * {"foo": [1,2]} will encode to "foo=1&foo=2". - * - * @param {!goog.Uri} uri A Uri object onto which the payload key value pairs - * will be encoded. - * - * @return {!goog.Uri} A reference to the Uri sent as a parameter. - * @private - */ -goog.net.Jsonp.addPayloadToUri_ = function(payload, uri) { - for (var name in payload) { - // NOTE(user): Safari/1.3 doesn't have hasOwnProperty(). In that - // case, we iterate over all properties as a very lame workaround. - if (!payload.hasOwnProperty || payload.hasOwnProperty(name)) { - uri.setParameterValues(name, payload[name]); - } - } - return uri; -}; - - -// WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING -// -// This class allows us (Google) to send data from non-Google and thus -// UNTRUSTED pages to our servers. Under NO CIRCUMSTANCES return -// anything sensitive, such as session or cookie specific data. Return -// only data that you want parties external to Google to have. Also -// NEVER use this method to send data from web pages to untrusted -// servers, or redirects to unknown servers (www.google.com/cache, -// /q=xx&btnl, /url, www.googlepages.com, etc.) -// -// WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/jsonp_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/jsonp_test.html.svn-base deleted file mode 100644 index f016153..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/jsonp_test.html.svn-base +++ /dev/null @@ -1,327 +0,0 @@ -<!DOCTYPE html> -<html> -<!-- -Copyright 2007 The Closure Library Authors. All Rights Reserved. - -Use of this source code is governed by the Apache License, Version 2.0. -See the COPYING file for details. ---> -<!-- ---> -<head> -<meta http-equiv="X-UA-Compatible" content="IE=edge"> -<title>Closure Unit Tests - goog.net.Jsonp</title> -<script src="../base.js"></script> -<script> - goog.require('goog.dom'); - goog.require('goog.net.Jsonp'); - goog.require('goog.testing.jsunit'); - goog.require('goog.userAgent'); - goog.require('goog.testing.recordFunction'); - goog.require('goog.testing.PropertyReplacer'); -</script> -</head> -<body> -<script> -// Global vars to facilitate a shared set up function. - -var timeoutWasCalled; -var timeoutHandler; - -var fakeUrl = 'http://fake-site.eek/'; - -var originalTimeout; -function setUp() { - timeoutWasCalled = false; - timeoutHandler = null; - originalTimeout = window.setTimeout; - window.setTimeout = function(handler, time) { - timeoutWasCalled = true; - timeoutHandler = handler; - }; -} - -// Firefox throws a JS error when a script is not found. We catch that here and -// ensure the test case doesn't fail because of it. -var originalOnError = window.onerror; -window.onerror = function(msg, url, line) { - // TODO(user): Safari 3 on the farm returns an object instead of the typcial - // params. Pass through errors for safari for now. - if (goog.userAgent.WEBKIT || - msg == 'Error loading script' && url.indexOf('fake-site') != -1) { - return true; - } else { - return originalOnError && originalOnError(msg, url, line); - } -}; - -function tearDown() { - window.setTimeout = originalTimeout; -} - -// Quick function records the before-state of the DOM, and then return a -// a function to check that XDC isn't leaving stuff behind. -function newCleanupGuard() { - var bodyChildCount = document.body.childNodes.length; - - return function() { - // let any timeout queues finish before we check these: - window.setTimeout(function() { - var propCounter = 0; - - // All callbacks should have been deleted or be the null function. - for (var id in goog.global[goog.net.Jsonp.CALLBACKS]) { - if (goog.global[goog.net.Jsonp.CALLBACKS][id] != goog.nullFunction) { - propCounter++; - } - } - - assertEquals( - 'script cleanup', bodyChildCount, document.body.childNodes.length); - assertEquals('window jsonp array empty', 0, propCounter); - }, 0); - } -} - -function getScriptElement(result) { - return result.deferred_.defaultScope_.script_; -} - - -// Check that send function is sane when things go well. -function testSend() { - var replyReceived; - var jsonp = new goog.net.Jsonp(fakeUrl); - - var checkCleanup = newCleanupGuard(); - - var userCallback = function(data) { - replyReceived = data; - } - - var payload = {atisket: 'atasket', basket: 'yellow'}; - var result = jsonp.send(payload, userCallback); - - var script = getScriptElement(result); - - assertNotNull('script created', script); - assertEquals('encoding is utf-8', 'UTF-8', script.charset); - - // Check that the URL matches our payload. - assertTrue('payload in url', script.src.indexOf('basket=yellow') > -1); - assertTrue('server url', script.src.indexOf(fakeUrl) == 0); - - // Now, we have to track down the name of the callback function, so we can - // call that to simulate a returned request + verify that the callback - // function does not break if it receives a second unexpected parameter. - var callbackName = /callback=([^&]+)/.exec(script.src)[1]; - var callbackFunc = eval(callbackName); - callbackFunc({some: 'data', another: ['data', 'right', 'here']}, - 'unexpected'); - assertEquals('input was received', 'right', replyReceived.another[1]); - - // Because the callbackFunc calls cleanUp_ and that calls setTimeout which - // we have overwritten, we have to call the timeoutHandler to actually do - // the cleaning. - timeoutHandler(); - - checkCleanup(); - timeoutHandler(); -} - - -// Check that send function is sane when things go well. -function testSendWhenCallbackHasTwoParameters() { - var replyReceived, replyReceived2; - var jsonp = new goog.net.Jsonp(fakeUrl); - - var checkCleanup = newCleanupGuard(); - - var userCallback = function(data, opt_data2) { - replyReceived = data; - replyReceived2 = opt_data2; - } - - var payload = {atisket: 'atasket', basket: 'yellow'}; - var result = jsonp.send(payload, userCallback); - var script = getScriptElement(result); - - // Test a callback function that receives two parameters. - var callbackName = /callback=([^&]+)/.exec(script.src)[1]; - var callbackFunc = eval(callbackName); - callbackFunc('param1', {some: 'data', another: ['data', 'right', 'here']}); - assertEquals('input was received', 'param1', replyReceived); - assertEquals('second input was received', 'right', - replyReceived2.another[1]); - - // Because the callbackFunc calls cleanUp_ and that calls setTimeout which - // we have overwritten, we have to call the timeoutHandler to actually do - // the cleaning. - timeoutHandler(); - - checkCleanup(); - timeoutHandler(); -} - -// Check that send function works correctly when callback param value is -// specified. -function testSendWithCallbackParamValue() { - var replyReceived; - var jsonp = new goog.net.Jsonp(fakeUrl); - - var checkCleanup = newCleanupGuard(); - - var userCallback = function(data) { - replyReceived = data; - } - - var payload = {atisket: 'atasket', basket: 'yellow'}; - var result = jsonp.send(payload, userCallback, undefined, 'dummyId'); - - var script = getScriptElement(result); - - assertNotNull('script created', script); - assertEquals('encoding is utf-8', 'UTF-8', script.charset); - - // Check that the URL matches our payload. - assertTrue('payload in url', script.src.indexOf('basket=yellow') > -1); - assertTrue('dummyId in url', - script.src.indexOf('callback=_callbacks_.dummyId') > -1); - assertTrue('server url', script.src.indexOf(fakeUrl) == 0); - - // Now, we simulate a returned request using the known callback function - // name. - var callbackFunc = _callbacks_.dummyId; - callbackFunc({some: 'data', another: ['data', 'right', 'here']}); - assertEquals('input was received', 'right', replyReceived.another[1]); - - // Because the callbackFunc calls cleanUp_ and that calls setTimeout which - // we have overwritten, we have to call the timeoutHandler to actually do - // the cleaning. - timeoutHandler(); - - checkCleanup(); - timeoutHandler(); -} - - -// Check that the send function is sane when the thing goes south. -function testSendFailure() { - var replyReceived = false; - var errorReplyReceived = false; - - var jsonp = new goog.net.Jsonp(fakeUrl); - - var checkCleanup = newCleanupGuard(); - - var userCallback = function(data) { - replyReceived = data; - } - var userErrorCallback = function(data) { - errorReplyReceived = data; - } - - var payload = { justa: 'test' }; - - jsonp.send(payload, userCallback, userErrorCallback); - - assertTrue('timeout called', timeoutWasCalled); - - // Now, simulate the time running out, so we go into error mode. - // After jsonp.send(), the timeoutHandler now is the Jsonp.cleanUp_ function. - timeoutHandler(); - // But that function also calls a setTimeout(), so it changes the timeout - // handler once again, so to actually clean up we have to call the - // timeoutHandler() once again. Fun! - timeoutHandler(); - - assertFalse('standard callback not called', replyReceived); - - // The user's error handler should be called back with the same payload - // passed back to it. - assertEquals('error handler called', 'test', errorReplyReceived.justa); - - // Check that the relevant cleanup has occurred. - checkCleanup(); - // Check cleanup just calls setTimeout so we have to call the handler to - // actually check that the cleanup worked. - timeoutHandler(); -} - - -// Check that a cancel call works and cleans up after itself. -function testCancel() { - var checkCleanup = newCleanupGuard(); - - var successCalled = false; - var successCallback = function() { - successCalled = true; - }; - - // Send and cancel a request, then make sure it was cleaned up. - var jsonp = new goog.net.Jsonp(fakeUrl); - var requestObject = jsonp.send({test: 'foo'}, successCallback); - jsonp.cancel(requestObject); - - for (var key in goog.global[goog.net.Jsonp.CALLBACKS]) { - assertNotEquals('The success callback should have been removed', - goog.global[goog.net.Jsonp.CALLBACKS][key], - successCallback); - } - - // Make sure cancelling removes the script tag - checkCleanup(); - timeoutHandler(); -} - -function testPayloadParameters() { - var checkCleanup = newCleanupGuard(); - - var jsonp = new goog.net.Jsonp(fakeUrl); - var result = jsonp.send({ - 'foo': 3, - 'bar': 'baz' - }); - - var script = getScriptElement(result); - assertEquals('Payload parameters should have been added to url.', - fakeUrl + '?foo=3&bar=baz', - script.src); - - checkCleanup(); - timeoutHandler(); -} - -function testOptionalPayload() { - var checkCleanup = newCleanupGuard(); - - var errorCallback = goog.testing.recordFunction(); - - var stubs = new goog.testing.PropertyReplacer(); - stubs.set(goog.global, 'setTimeout', function(errorHandler) { - errorHandler(); - }); - - var jsonp = new goog.net.Jsonp(fakeUrl); - var result = jsonp.send(null, null, errorCallback); - - var script = getScriptElement(result); - assertEquals('Parameters should not have been added to url.', - fakeUrl, script.src); - - // Clear the script hooks because we triggered the error manually. - script.onload = goog.nullFunction; - script.onerror = goog.nullFunction; - script.onreadystatechange = goog.nullFunction; - - var errorCallbackArguments = errorCallback.getLastCall().getArguments(); - assertEquals(1, errorCallbackArguments.length); - assertNull(errorCallbackArguments[0]); - - checkCleanup(); - stubs.reset(); -} - -</script> -</body> -</html> diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/mockiframeio.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/mockiframeio.js.svn-base deleted file mode 100644 index 13423fd..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/mockiframeio.js.svn-base +++ /dev/null @@ -1,318 +0,0 @@ -// Copyright 2007 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Mock of IframeIo for unit testing. - */ - -goog.provide('goog.net.MockIFrameIo'); -goog.require('goog.events.EventTarget'); -goog.require('goog.net.ErrorCode'); -goog.require('goog.net.IframeIo'); -goog.require('goog.net.IframeIo.IncrementalDataEvent'); - - - -/** - * Mock implenetation of goog.net.IframeIo. This doesn't provide a mock - * implementation for all cases, but it's not too hard to add them as needed. - * @param {goog.testing.TestQueue} testQueue Test queue for inserting test - * events. - * @constructor - * @extends {goog.events.EventTarget} - */ -goog.net.MockIFrameIo = function(testQueue) { - goog.events.EventTarget.call(this); - - /** - * Queue of events write to - * @type {goog.testing.TestQueue} - * @private - */ - this.testQueue_ = testQueue; - -}; -goog.inherits(goog.net.MockIFrameIo, goog.events.EventTarget); - - -/** - * Whether MockIFrameIo is active. - * @type {boolean} - * @private - */ -goog.net.MockIFrameIo.prototype.active_ = false; - - -/** - * Last content. - * @type {string} - * @private - */ -goog.net.MockIFrameIo.prototype.lastContent_ = ''; - - -/** - * Last error code. - * @type {goog.net.ErrorCode} - * @private - */ -goog.net.MockIFrameIo.prototype.lastErrorCode_ = goog.net.ErrorCode.NO_ERROR; - - -/** - * Last error message. - * @type {string} - * @private - */ -goog.net.MockIFrameIo.prototype.lastError_ = ''; - - -/** - * Last custom error. - * @type {Object} - * @private - */ -goog.net.MockIFrameIo.prototype.lastCustomError_ = null; - - -/** - * Last URI. - * @type {goog.Uri} - * @private - */ -goog.net.MockIFrameIo.prototype.lastUri_ = null; - - -/** - * Simulates the iframe send. - * - * @param {goog.Uri|string} uri Uri of the request. - * @param {string=} opt_method Default is GET, POST uses a form to submit the - * request. - * @param {boolean=} opt_noCache Append a timestamp to the request to avoid - * caching. - * @param {Object|goog.structs.Map=} opt_data Map of key-value pairs. - */ -goog.net.MockIFrameIo.prototype.send = function(uri, opt_method, opt_noCache, - opt_data) { - if (this.active_) { - throw Error('[goog.net.IframeIo] Unable to send, already active.'); - } - - this.testQueue_.enqueue(['s', uri, opt_method, opt_noCache, opt_data]); - this.complete_ = false; - this.active_ = true; -}; - - -/** - * Simulates the iframe send from a form. - * @param {Element} form Form element used to send the request to the server. - * @param {string=} opt_uri Uri to set for the destination of the request, by - * default the uri will come from the form. - * @param {boolean=} opt_noCache Append a timestamp to the request to avoid - * caching. - */ -goog.net.MockIFrameIo.prototype.sendFromForm = function(form, opt_uri, - opt_noCache) { - if (this.active_) { - throw Error('[goog.net.IframeIo] Unable to send, already active.'); - } - - this.testQueue_.enqueue(['s', form, opt_uri, opt_noCache]); - this.complete_ = false; - this.active_ = true; -}; - - -/** - * Simulates aborting the current Iframe request. - * @param {goog.net.ErrorCode=} opt_failureCode Optional error code to use - - * defaults to ABORT. - */ -goog.net.MockIFrameIo.prototype.abort = function(opt_failureCode) { - if (this.active_) { - this.testQueue_.enqueue(['a', opt_failureCode]); - this.complete_ = false; - this.active_ = false; - this.success_ = false; - this.lastErrorCode_ = opt_failureCode || goog.net.ErrorCode.ABORT; - this.dispatchEvent(goog.net.EventType.ABORT); - this.simulateReady(); - } -}; - - -/** - * Simulates receive of incremental data. - * @param {Object} data Data. - */ -goog.net.MockIFrameIo.prototype.simulateIncrementalData = function(data) { - this.dispatchEvent(new goog.net.IframeIo.IncrementalDataEvent(data)); -}; - - -/** - * Simulates the iframe is done. - * @param {goog.net.ErrorCode} errorCode The error code for any error that - * should be simulated. - */ -goog.net.MockIFrameIo.prototype.simulateDone = function(errorCode) { - if (errorCode) { - this.success_ = false; - this.lastErrorCode_ = goog.net.ErrorCode.HTTP_ERROR; - this.lastError_ = this.getLastError(); - this.dispatchEvent(goog.net.EventType.ERROR); - } else { - this.success_ = true; - this.lastErrorCode_ = goog.net.ErrorCode.NO_ERROR; - this.dispatchEvent(goog.net.EventType.SUCCESS); - } - this.complete_ = true; - this.dispatchEvent(goog.net.EventType.COMPLETE); -}; - - -/** - * Simulates the IFrame is ready for the next request. - */ -goog.net.MockIFrameIo.prototype.simulateReady = function() { - this.dispatchEvent(goog.net.EventType.READY); -}; - - -/** - * @return {boolean} True if transfer is complete. - */ -goog.net.MockIFrameIo.prototype.isComplete = function() { - return this.complete_; -}; - - -/** - * @return {boolean} True if transfer was successful. - */ -goog.net.MockIFrameIo.prototype.isSuccess = function() { - return this.success_; -}; - - -/** - * @return {boolean} True if a transfer is in progress. - */ -goog.net.MockIFrameIo.prototype.isActive = function() { - return this.active_; -}; - - -/** - * Returns the last response text (i.e. the text content of the iframe). - * Assumes plain text! - * @return {string} Result from the server. - */ -goog.net.MockIFrameIo.prototype.getResponseText = function() { - return this.lastContent_; -}; - - -/** - * Parses the content as JSON. This is a safe parse and may throw an error - * if the response is malformed. - * @return {Object} The parsed content. - */ -goog.net.MockIFrameIo.prototype.getResponseJson = function() { - return goog.json.parse(this.lastContent_); -}; - - -/** - * Get the uri of the last request. - * @return {goog.Uri} Uri of last request. - */ -goog.net.MockIFrameIo.prototype.getLastUri = function() { - return this.lastUri_; -}; - - -/** - * Gets the last error code. - * @return {goog.net.ErrorCode} Last error code. - */ -goog.net.MockIFrameIo.prototype.getLastErrorCode = function() { - return this.lastErrorCode_; -}; - - -/** - * Gets the last error message. - * @return {string} Last error message. - */ -goog.net.MockIFrameIo.prototype.getLastError = function() { - return goog.net.ErrorCode.getDebugMessage(this.lastErrorCode_); -}; - - -/** - * Gets the last custom error. - * @return {Object} Last custom error. - */ -goog.net.MockIFrameIo.prototype.getLastCustomError = function() { - return this.lastCustomError_; -}; - - -/** - * Sets the callback function used to check if a loaded IFrame is in an error - * state. - * @param {Function} fn Callback that expects a document object as it's single - * argument. - */ -goog.net.MockIFrameIo.prototype.setErrorChecker = function(fn) { - this.errorChecker_ = fn; -}; - - -/** - * Gets the callback function used to check if a loaded IFrame is in an error - * state. - * @return {Function} A callback that expects a document object as it's single - * argument. - */ -goog.net.MockIFrameIo.prototype.getErrorChecker = function() { - return this.errorChecker_; -}; - - -/** - * Returns the number of milliseconds after which an incomplete request will be - * aborted, or 0 if no timeout is set. - * @return {number} Timeout interval in milliseconds. - */ -goog.net.MockIFrameIo.prototype.getTimeoutInterval = function() { - return this.timeoutInterval_; -}; - - -/** - * Sets the number of milliseconds after which an incomplete request will be - * aborted and a {@link goog.net.EventType.TIMEOUT} event raised; 0 means no - * timeout is set. - * @param {number} ms Timeout interval in milliseconds; 0 means none. - */ -goog.net.MockIFrameIo.prototype.setTimeoutInterval = function(ms) { - // TODO (pupius) - never used - doesn't look like timeouts were implemented - this.timeoutInterval_ = Math.max(0, ms); -}; - - diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/mockxhrlite.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/mockxhrlite.js.svn-base deleted file mode 100644 index 2ff5995..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/mockxhrlite.js.svn-base +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2007 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Mock of XhrLite for unit testing. - * - */ - -goog.provide('goog.net.MockXhrLite'); - -goog.require('goog.testing.net.XhrIo'); - - - -/** - * Mock implementation of goog.net.XhrLite. This doesn't provide a mock - * implementation for all cases, but it's not too hard to add them as needed. - * @param {goog.testing.TestQueue=} opt_testQueue Test queue for inserting test - * events. - * @deprecated Use goog.testing.net.XhrIo. - * @constructor - */ -goog.net.MockXhrLite = goog.testing.net.XhrIo; diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/mockxhrlite_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/mockxhrlite_test.html.svn-base deleted file mode 100644 index c52743a..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/mockxhrlite_test.html.svn-base +++ /dev/null @@ -1,109 +0,0 @@ -<!DOCTYPE html> -<html> -<!-- -Copyright 2008 The Closure Library Authors. All Rights Reserved. - -Use of this source code is governed by the Apache License, Version 2.0. -See the COPYING file for details. ---> -<head> -<meta http-equiv="X-UA-Compatible" content="IE=edge"> -<title>Closure Unit Tests - goog.net.MockXhrLite</title> -<script src="../base.js"></script> -<script> - goog.require('goog.dom.xml'); - goog.require('goog.events'); - goog.require('goog.net.MockXhrLite'); - goog.require('goog.testing.asserts'); - goog.require('goog.testing.jsunit'); -</script> -</head> -<body> -<script> - -function testGetResponseText() { - // Text response came. - var called = false; - var xhr = new goog.net.MockXhrLite(); - goog.events.listen(xhr, goog.net.EventType.SUCCESS, function(e) { - called = true; - assertEquals('text', e.target.getResponseText()); - }); - xhr.simulateResponse(200, 'text'); - assertTrue(called); - - // XML response came. - var called = false; - var xhr = new goog.net.MockXhrLite(); - var xml = goog.dom.xml.createDocument(); - xml.appendChild(xml.createElement('root')); - goog.events.listen(xhr, goog.net.EventType.SUCCESS, function(e) { - called = true; - var text = e.target.getResponseText(); - assertTrue(/<root ?\/>/.test(text)); - }); - xhr.simulateResponse(200, xml); - assertTrue(called); -} - -function testGetResponseJson() { - // Valid JSON response came. - var called = false; - var xhr = new goog.net.MockXhrLite(); - goog.events.listen(xhr, goog.net.EventType.SUCCESS, function(e) { - called = true; - assertArrayEquals([0, 1], e.target.getResponseJson()); - }); - xhr.simulateResponse(200, '[0, 1]'); - assertTrue(called); - - // Invalid JSON response came. - var called = false; - var xhr = new goog.net.MockXhrLite(); - goog.events.listen(xhr, goog.net.EventType.SUCCESS, function(e) { - called = true; - assertThrows(e.target.getResponseJson); - }); - xhr.simulateResponse(200, '[0, 1'); - assertTrue(called); - - // XML response came. - var called = false; - var xhr = new goog.net.MockXhrLite(); - var xml = goog.dom.xml.createDocument(); - xml.appendChild(xml.createElement('root')); - goog.events.listen(xhr, goog.net.EventType.SUCCESS, function(e) { - called = true; - assertThrows(e.target.getResponseJson); - }); - xhr.simulateResponse(200, xml); - assertTrue(called); -} - -function testGetResponseXml() { - // Text response came. - var called = false; - var xhr = new goog.net.MockXhrLite(); - goog.events.listen(xhr, goog.net.EventType.SUCCESS, function(e) { - called = true; - assertNull(e.target.getResponseXml()); - }); - xhr.simulateResponse(200, 'text'); - assertTrue(called); - - // XML response came. - var called = false; - var xhr = new goog.net.MockXhrLite(); - var xml = goog.dom.xml.createDocument(); - xml.appendChild(xml.createElement('root')); - goog.events.listen(xhr, goog.net.EventType.SUCCESS, function(e) { - called = true; - assertEquals(xml, e.target.getResponseXml()); - }); - xhr.simulateResponse(200, xml); - assertTrue(called); -} - -</script> -</body> -</html> diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/multiiframeloadmonitor.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/multiiframeloadmonitor.js.svn-base deleted file mode 100644 index 721f5cc..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/multiiframeloadmonitor.js.svn-base +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright 2008 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Class that can be used to determine when multiple iframes have - * been loaded. Refactored from static APIs in IframeLoadMonitor. - */ -goog.provide('goog.net.MultiIframeLoadMonitor'); - -goog.require('goog.net.IframeLoadMonitor'); - - - -/** - * Provides a wrapper around IframeLoadMonitor, to allow the caller to wait for - * multiple iframes to load. - * - * @param {Array.<HTMLIFrameElement>} iframes Array of iframe elements to - * wait until they are loaded. - * @param {function():void} callback The callback to invoke once the frames have - * loaded. - * @param {boolean=} opt_hasContent true if the monitor should wait until the - * iframes have content (body.firstChild != null). - * @constructor - */ -goog.net.MultiIframeLoadMonitor = function(iframes, callback, opt_hasContent) { - /** - * Array of IframeLoadMonitors we use to track the loaded status of any - * currently unloaded iframes. - * @type {Array.<goog.net.IframeLoadMonitor>} - * @private - */ - this.pendingIframeLoadMonitors_ = []; - - /** - * Callback which is invoked when all of the iframes are loaded. - * @type {function():void} - * @private - */ - this.callback_ = callback; - - for (var i = 0; i < iframes.length; i++) { - var iframeLoadMonitor = new goog.net.IframeLoadMonitor( - iframes[i], opt_hasContent); - if (iframeLoadMonitor.isLoaded()) { - // Already loaded - don't need to wait - iframeLoadMonitor.dispose(); - } else { - // Iframe isn't loaded yet - register to be notified when it is - // loaded, and track this monitor so we can dispose later as - // required. - this.pendingIframeLoadMonitors_.push(iframeLoadMonitor); - goog.events.listen( - iframeLoadMonitor, goog.net.IframeLoadMonitor.LOAD_EVENT, this); - } - } - if (!this.pendingIframeLoadMonitors_.length) { - // All frames were already loaded - this.callback_(); - } -}; - - -/** - * Handles a pending iframe load monitor load event. - * @param {goog.events.Event} e The goog.net.IframeLoadMonitor.LOAD_EVENT event. - */ -goog.net.MultiIframeLoadMonitor.prototype.handleEvent = function(e) { - var iframeLoadMonitor = e.target; - // iframeLoadMonitor is now loaded, remove it from the array of - // pending iframe load monitors. - for (var i = 0; i < this.pendingIframeLoadMonitors_.length; i++) { - if (this.pendingIframeLoadMonitors_[i] == iframeLoadMonitor) { - this.pendingIframeLoadMonitors_.splice(i, 1); - break; - } - } - - // Disposes of the iframe load monitor. We created this iframe load monitor - // and installed the single listener on it, so it is safe to dispose it - // in the middle of this event handler. - iframeLoadMonitor.dispose(); - - // If there are no more pending iframe load monitors, all the iframes - // have loaded, and so we invoke the callback. - if (!this.pendingIframeLoadMonitors_.length) { - this.callback_(); - } -}; - - -/** - * Stops monitoring the iframes, cleaning up any associated resources. In - * general, the object cleans up its own resources before invoking the - * callback, so this API should only be used if the caller wants to stop the - * monitoring before the iframes are loaded (for example, if the caller is - * implementing a timeout). - */ -goog.net.MultiIframeLoadMonitor.prototype.stopMonitoring = function() { - for (var i = 0; i < this.pendingIframeLoadMonitors_.length; i++) { - this.pendingIframeLoadMonitors_[i].dispose(); - } - this.pendingIframeLoadMonitors_.length = 0; -}; - diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/multiiframeloadmonitor_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/multiiframeloadmonitor_test.html.svn-base deleted file mode 100644 index 7b7696d..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/multiiframeloadmonitor_test.html.svn-base +++ /dev/null @@ -1,172 +0,0 @@ -<!DOCTYPE html> -<html> -<!-- -Copyright 2008 The Closure Library Authors. All Rights Reserved. - -Use of this source code is governed by the Apache License, Version 2.0. -See the COPYING file for details. ---> -<!-- ---> -<head> -<meta http-equiv="X-UA-Compatible" content="IE=edge"> - <title>Closure Unit Tests - goog.net.MultiIframeLoadMonitor</title> - <script src="../base.js"></script> - <script> - goog.require('goog.dom'); - goog.require('goog.events'); - goog.require('goog.net.MultiIframeLoadMonitor'); - goog.require('goog.testing.AsyncTestCase'); - goog.require('goog.testing.jsunit'); - </script> -</head> -<body> -<div id="frame_parent"></div> -<script> - var TEST_FRAME_SRCS = ['iframeloadmonitor_test_frame.html', - 'iframeloadmonitor_test_frame2.html', - 'iframeloadmonitor_test_frame3.html']; - - // Create a new test case. - var iframeLoaderTestCase = new goog.testing.AsyncTestCase(document.title); - iframeLoaderTestCase.stepTimeout = 4 * 1000; - - // How many multpile frames finished loading - iframeLoaderTestCase.multipleComplete_ = 0; - - iframeLoaderTestCase.numMonitors = 0; - iframeLoaderTestCase.disposeCalled = 0; - - /** Sets up the test environment, adds tests and sets up the worker pools. */ - iframeLoaderTestCase.setUpPage = function() { - this.log('Setting tests up'); - iframeLoaderTestCase.waitForAsync('loading iframes'); - - var dom = goog.dom.getDomHelper(); - - // Load multiple with callback - var frame1 = dom.createDom('iframe'); - var frame2 = dom.createDom('iframe'); - var multiMonitor = new goog.net.MultiIframeLoadMonitor( - [frame1, frame2], goog.bind(this.multipleCallback, this)); - this.log('Loading frames at: ' + TEST_FRAME_SRCS[0] + ' and ' - + TEST_FRAME_SRCS[1]); - // Make sure they don't look loaded yet. - assertEquals(0, this.multipleComplete_); - var frameParent = dom.getElement('frame_parent'); - dom.appendChild(frameParent, frame1); - frame1.src = TEST_FRAME_SRCS[0]; - dom.appendChild(frameParent, frame2); - frame2.src = TEST_FRAME_SRCS[1]; - - // Load multiple with callback and content check - var frame3 = dom.createDom('iframe'); - var frame4 = dom.createDom('iframe'); - var multiMonitor = new goog.net.MultiIframeLoadMonitor( - [frame3, frame4], goog.bind(this.multipleContentCallback, this), true); - this.log('Loading frames with content check at: ' + TEST_FRAME_SRCS[1] + - ' and ' + TEST_FRAME_SRCS[2]); - dom.appendChild(frameParent, frame3); - frame3.src = TEST_FRAME_SRCS[1]; - dom.appendChild(frameParent, frame4); - frame4.src = TEST_FRAME_SRCS[2]; - - this.add(new goog.testing.TestCase.Test( - 'test results', this.testResults, this)); - this.add(new goog.testing.TestCase.Test( - 'stopMonitoring', this.testStop, this)); - }; - - - /** Callback for the multiple frame load test case */ - iframeLoaderTestCase.multipleCallback = function() { - this.log('multiple frames finished loading'); - this.multipleComplete_++; - this.multipleCompleteNoContent_ = true; - this.callbacksComplete(); - }; - - /** Callback for the multiple frame with content load test case */ - iframeLoaderTestCase.multipleContentCallback = function() { - this.log('multiple frames with content finished loading'); - this.multipleComplete_++; - this.multipleCompleteContent_ = true; - this.callbacksComplete(); - }; - - /** Checks if all the load callbacks are done*/ - iframeLoaderTestCase.callbacksComplete = function() { - if (this.multipleComplete_ == 2) { - iframeLoaderTestCase.continueTesting(); - } - } - - /** Tests the results. */ - iframeLoaderTestCase.testResults = function() { - this.log('getting test results'); - assertTrue(this.multipleCompleteNoContent_); - assertTrue(this.multipleCompleteContent_); - }; - - iframeLoaderTestCase.fakeLoadMonitor = function() { - // Replaces IframeLoadMonitor with a fake version that just tracks - // instantiations/disposals - this.loadMonitorConstructor = goog.net.IframeLoadMonitor; - var that = this; - goog.net.IframeLoadMonitor = function() { - that.numMonitors++; - return { - isLoaded: function() { return false; }, - dispose: function() { that.disposeCalled++; }, - attachEvent: function() {} - }; - } - goog.net.IframeLoadMonitor.LOAD_EVENT = 'ifload'; - }; - - iframeLoaderTestCase.unfakeLoadMonitor = function() { - goog.net.IframeLoadMonitor = this.loadMonitorConstructor; - }; - - - iframeLoaderTestCase.testStop = function() { - // create two unloaded frames, make sure that load monitors are loaded - // behind the scenes, then make sure they are disposed properly. - this.fakeLoadMonitor(); - var dom = goog.dom.getDomHelper(); - var frames = [dom.createDom('iframe'), dom.createDom('iframe')]; - var multiMonitor = new goog.net.MultiIframeLoadMonitor( - frames, - function() { - fail("should not invoke callback for unloaded rames"); - }); - assertEquals(frames.length, this.numMonitors); - assertEquals(0, this.disposeCalled); - multiMonitor.stopMonitoring(); - assertEquals(frames.length, this.disposeCalled); - this.unfakeLoadMonitor(); - }; - - /** Used by the JsUnit test runner. */ - function testResults() { - iframeLoaderTestCase.testResults(); - } - - /** Used by the JsUnit test runner. */ - function testDispose() { - iframeLoaderTestCase.testDispose(); - } - - /** Used by the JsUnit test runner. */ - function setUpPage() { - iframeLoaderTestCase.runTests(); - } - - /** Standalone Closure Test Runner. */ - if (typeof G_testRunner != 'undefined') { - G_testRunner.initialize(iframeLoaderTestCase); - } - -</script> -</body> -</html> diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/networktester.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/networktester.js.svn-base deleted file mode 100644 index 972abab..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/networktester.js.svn-base +++ /dev/null @@ -1,383 +0,0 @@ -// Copyright 2007 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Definition of goog.net.NetworkTester. - */ - -goog.provide('goog.net.NetworkTester'); -goog.require('goog.Timer'); -goog.require('goog.Uri'); -goog.require('goog.debug.Logger'); - - - -/** - * Creates an instance of goog.net.NetworkTester which can be used to test - * for internet connectivity by seeing if an image can be loaded from - * google.com. It can also be tested with other URLs. - * @param {Function} callback Callback that is called when the test completes. - * The callback takes a single boolean parameter. True indicates the URL - * was reachable, false indicates it wasn't. - * @param {Object=} opt_handler Handler object for the callback. - * @param {goog.Uri=} opt_uri URI to use for testing. - * @constructor - */ -goog.net.NetworkTester = function(callback, opt_handler, opt_uri) { - /** - * Callback that is called when the test completes. - * The callback takes a single boolean parameter. True indicates the URL was - * reachable, false indicates it wasn't. - * @type {Function} - * @private - */ - this.callback_ = callback; - - /** - * Handler object for the callback. - * @type {Object|undefined} - * @private - */ - this.handler_ = opt_handler; - - if (!opt_uri) { - // set the default URI to be based on the cleardot image at google.com - // We need to add a 'rand' to make sure the response is not fulfilled - // by browser cache. Use protocol-relative URLs to avoid insecure content - // warnings in IE. - opt_uri = new goog.Uri('//www.google.com/images/cleardot.gif'); - opt_uri.makeUnique(); - } - - /** - * Uri to use for test. Defaults to using an image off of google.com - * @type {goog.Uri} - * @private - */ - this.uri_ = opt_uri; -}; - - -/** - * Default timeout - * @type {number} - */ -goog.net.NetworkTester.DEFAULT_TIMEOUT_MS = 10000; - - -/** - * Logger object - * @type {goog.debug.Logger} - * @private - */ -goog.net.NetworkTester.prototype.logger_ = - goog.debug.Logger.getLogger('goog.net.NetworkTester'); - - -/** - * Timeout for test - * @type {number} - * @private - */ -goog.net.NetworkTester.prototype.timeoutMs_ = - goog.net.NetworkTester.DEFAULT_TIMEOUT_MS; - - -/** - * Whether we've already started running. - * @type {boolean} - * @private - */ -goog.net.NetworkTester.prototype.running_ = false; - - -/** - * Number of retries to attempt - * @type {number} - * @private - */ -goog.net.NetworkTester.prototype.retries_ = 0; - - -/** - * Attempt number we're on - * @type {number} - * @private - */ -goog.net.NetworkTester.prototype.attempt_ = 0; - - -/** - * Pause between retries in milliseconds. - * @type {number} - * @private - */ -goog.net.NetworkTester.prototype.pauseBetweenRetriesMs_ = 0; - - -/** - * Timer for timeouts. - * @type {?number} - * @private - */ -goog.net.NetworkTester.prototype.timeoutTimer_ = null; - - -/** - * Timer for pauses between retries. - * @type {?number} - * @private - */ -goog.net.NetworkTester.prototype.pauseTimer_ = null; - - -/** - * Returns the timeout in milliseconds. - * @return {number} Timeout in milliseconds. - */ -goog.net.NetworkTester.prototype.getTimeout = function() { - return this.timeoutMs_; -}; - - -/** - * Sets the timeout in milliseconds. - * @param {number} timeoutMs Timeout in milliseconds. - */ -goog.net.NetworkTester.prototype.setTimeout = function(timeoutMs) { - this.timeoutMs_ = timeoutMs; -}; - - -/** - * Returns the numer of retries to attempt. - * @return {number} Number of retries to attempt. - */ -goog.net.NetworkTester.prototype.getNumRetries = function() { - return this.retries_; -}; - - -/** - * Sets the timeout in milliseconds. - * @param {number} retries Number of retries to attempt. - */ -goog.net.NetworkTester.prototype.setNumRetries = function(retries) { - this.retries_ = retries; -}; - - -/** - * Returns the pause between retries in milliseconds. - * @return {number} Pause between retries in milliseconds. - */ -goog.net.NetworkTester.prototype.getPauseBetweenRetries = function() { - return this.pauseBetweenRetriesMs_; -}; - - -/** - * Sets the pause between retries in milliseconds. - * @param {number} pauseMs Pause between retries in milliseconds. - */ -goog.net.NetworkTester.prototype.setPauseBetweenRetries = function(pauseMs) { - this.pauseBetweenRetriesMs_ = pauseMs; -}; - - -/** - * Returns the uri to use for the test. - * @return {goog.Uri} The uri for the test. - */ -goog.net.NetworkTester.prototype.getUri = function() { - return this.uri_; -}; - - -/** - * Sets the uri to use for the test. - * @param {goog.Uri} uri The uri for the test. - */ -goog.net.NetworkTester.prototype.setUri = function(uri) { - this.uri_ = uri; -}; - - -/** - * Returns whether the tester is currently running. - * @return {boolean} True if it's running, false if it's not running. - */ -goog.net.NetworkTester.prototype.isRunning = function() { - return this.running_; -}; - - -/** - * Starts the process of testing the network. - */ -goog.net.NetworkTester.prototype.start = function() { - if (this.running_) { - throw Error('NetworkTester.start called when already running'); - } - this.running_ = true; - - this.logger_.info('Starting'); - this.attempt_ = 0; - this.startNextAttempt_(); -}; - - -/** - * Stops the testing of the network. This is a noop if not running. - */ -goog.net.NetworkTester.prototype.stop = function() { - this.cleanupCallbacks_(); - this.running_ = false; -}; - - -/** - * Starts the next attempt to load an image. - * @private - */ -goog.net.NetworkTester.prototype.startNextAttempt_ = function() { - this.attempt_++; - - if (goog.net.NetworkTester.getNavigatorOffline_()) { - this.logger_.info('Browser is set to work offline.'); - // Call in a timeout to make async like the rest. - goog.Timer.callOnce(goog.bind(this.onResult, this, false), 0); - } else { - this.logger_.info('Loading image (attempt ' + this.attempt_ + - ') at ' + this.uri_); - this.image_ = new Image(); - this.image_.onload = goog.bind(this.onImageLoad_, this); - this.image_.onerror = goog.bind(this.onImageError_, this); - this.image_.onabort = goog.bind(this.onImageAbort_, this); - - this.timeoutTimer_ = goog.Timer.callOnce(this.onImageTimeout_, - this.timeoutMs_, this); - this.image_.src = String(this.uri_); - } -}; - - -/** - * @return {boolean} Whether navigator.onLine returns false. - * @private - */ -goog.net.NetworkTester.getNavigatorOffline_ = function() { - return 'onLine' in navigator && !navigator.onLine; -}; - - -/** - * Callback for the image successfully loading. - * @private - */ -goog.net.NetworkTester.prototype.onImageLoad_ = function() { - this.logger_.info('Image loaded'); - this.onResult(true); -}; - - -/** - * Callback for the image failing to load. - * @private - */ -goog.net.NetworkTester.prototype.onImageError_ = function() { - this.logger_.info('Image load error'); - this.onResult(false); -}; - - -/** - * Callback for the image load being aborted. - * @private - */ -goog.net.NetworkTester.prototype.onImageAbort_ = function() { - this.logger_.info('Image load aborted'); - this.onResult(false); -}; - - -/** - * Callback for the image load timing out. - * @private - */ -goog.net.NetworkTester.prototype.onImageTimeout_ = function() { - this.logger_.info('Image load timed out'); - this.onResult(false); -}; - - -/** - * Handles a successful or failed result. - * @param {boolean} succeeded Whether the image load succeeded. - */ -goog.net.NetworkTester.prototype.onResult = function(succeeded) { - this.cleanupCallbacks_(); - - if (succeeded) { - this.running_ = false; - this.callback_.call(this.handler_, true); - } else { - if (this.attempt_ <= this.retries_) { - if (this.pauseBetweenRetriesMs_) { - this.pauseTimer_ = goog.Timer.callOnce(this.onPauseFinished_, - this.pauseBetweenRetriesMs_, this); - } else { - this.startNextAttempt_(); - } - } else { - this.running_ = false; - this.callback_.call(this.handler_, false); - } - } -}; - - -/** - * Callback for the pause between retry timer. - * @private - */ -goog.net.NetworkTester.prototype.onPauseFinished_ = function() { - this.pauseTimer_ = null; - this.startNextAttempt_(); -}; - - -/** - * Cleans up the handlers and timer associated with the image. - * @private - */ -goog.net.NetworkTester.prototype.cleanupCallbacks_ = function() { - // clear handlers to avoid memory leaks - // NOTE(user): Nullified individually to avoid compiler warnings - // (BUG 658126) - if (this.image_) { - this.image_.onload = null; - this.image_.onerror = null; - this.image_.onabort = null; - this.image_ = null; - } - if (this.timeoutTimer_) { - goog.Timer.clear(this.timeoutTimer_); - this.timeoutTimer_ = null; - } - if (this.pauseTimer_) { - goog.Timer.clear(this.pauseTimer_); - this.pauseTimer_ = null; - } -}; diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/networktester_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/networktester_test.html.svn-base deleted file mode 100644 index 67fc4ad..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/networktester_test.html.svn-base +++ /dev/null @@ -1,227 +0,0 @@ -<!DOCTYPE html> -<html> -<!-- -Copyright 2006 The Closure Library Authors. All Rights Reserved. - -Use of this source code is governed by the Apache License, Version 2.0. -See the COPYING file for details. ---> -<head> -<meta http-equiv="X-UA-Compatible" content="IE=edge"> -<title>Closure Unit Tests - goog.net.NetworkTester</title> -<script src="../base.js"></script> -<script> - goog.require('goog.Uri') - goog.require('goog.net.NetworkTester'); - goog.require('goog.testing.MockClock'); - goog.require('goog.testing.jsunit'); -</script> -</head> -<body> - -<script> - var clock; - - function setUp() { - clock = new goog.testing.MockClock(true); - } - - function tearDown() { - clock.dispose(); - } - - function testSuccess() { - // set up the tster - var handler = new Handler(); - var tester = new goog.net.NetworkTester(handler.callback, handler); - assertFalse(tester.isRunning()); - tester.start(); - assertTrue(handler.isEmpty()); - assertTrue(tester.isRunning()); - - // simulate the image load and verify - var image = tester.image_; - assertEquals(String(tester.getUri()), image.src); - assertTrue(handler.isEmpty()); - image.onload.call(null); - assertTrue(handler.dequeue()); - assertFalse(tester.isRunning()); - } - - function testFailure() { - // set up the tester - var handler = new Handler(); - var tester = new goog.net.NetworkTester(handler.callback, handler); - assertFalse(tester.isRunning()); - tester.start(); - assertTrue(handler.isEmpty()); - assertTrue(tester.isRunning()); - - // simulate the image failure and verify - var image = tester.image_; - assertEquals(String(tester.getUri()), image.src); - assertTrue(handler.isEmpty()); - image.onerror.call(null); - assertFalse(handler.dequeue()); - assertFalse(tester.isRunning()); - } - - function testAbort() { - // set up the tester - var handler = new Handler(); - var tester = new goog.net.NetworkTester(handler.callback, handler); - assertFalse(tester.isRunning()); - tester.start(); - assertTrue(handler.isEmpty()); - assertTrue(tester.isRunning()); - - // simulate the image abort and verify - var image = tester.image_; - assertEquals(String(tester.getUri()), image.src); - assertTrue(handler.isEmpty()); - image.onabort.call(null); - assertFalse(handler.dequeue()); - assertFalse(tester.isRunning()); - } - - function testTimeout() { - // set up the tester - var handler = new Handler(); - var tester = new goog.net.NetworkTester(handler.callback, handler); - assertFalse(tester.isRunning()); - tester.start(); - assertTrue(handler.isEmpty()); - assertTrue(tester.isRunning()); - - // simulate the image timeout and verify - var image = tester.image_; - assertEquals(String(tester.getUri()), image.src); - assertTrue(handler.isEmpty()); - clock.tick(10000); - assertFalse(handler.dequeue()); - assertFalse(tester.isRunning()); - } - - function testRetries() { - // set up the tester - var handler = new Handler(); - var tester = new goog.net.NetworkTester(handler.callback, handler); - tester.setNumRetries(1); - assertFalse(tester.isRunning()); - tester.start(); - assertTrue(handler.isEmpty()); - assertTrue(tester.isRunning()); - - // try number 1 fails - var image = tester.image_; - assertEquals(String(tester.getUri()), image.src); - assertTrue(handler.isEmpty()); - image.onerror.call(null); - assertTrue(handler.isEmpty()); - assertTrue(tester.isRunning()); - - // try number 2 succeeds - image = tester.image_; - assertEquals(String(tester.getUri()), image.src); - assertTrue(handler.isEmpty()); - image.onload.call(null); - assertTrue(handler.dequeue()); - assertFalse(tester.isRunning()); - } - - function testPauseBetweenRetries() { - // set up the tester - var handler = new Handler(); - var tester = new goog.net.NetworkTester(handler.callback, handler); - tester.setNumRetries(1); - tester.setPauseBetweenRetries(1000); - assertFalse(tester.isRunning()); - tester.start(); - assertTrue(handler.isEmpty()); - assertTrue(tester.isRunning()); - - // try number 1 fails - var image = tester.image_; - assertEquals(String(tester.getUri()), image.src); - assertTrue(handler.isEmpty()); - image.onerror.call(null); - assertTrue(handler.isEmpty()); - assertTrue(tester.isRunning()); - - // need to pause 1000 ms for the second attempt - assertNull(tester.image_); - clock.tick(1000); - - // try number 2 succeeds - image = tester.image_; - assertEquals(String(tester.getUri()), image.src); - assertTrue(handler.isEmpty()); - image.onload.call(null); - assertTrue(handler.dequeue()); - assertFalse(tester.isRunning()); - } - - function testNonDefaultUri() { - var handler = new Handler(); - var newUri = new goog.Uri('//www.google.com/images/cleardot2.gif'); - var tester = new goog.net.NetworkTester(handler.callback, handler, newUri); - var testerUri = tester.getUri(); - assertTrue(testerUri.toString().indexOf('cleardot2') > -1); - } - - function testOffline() { - - // set up the tester - var handler = new Handler(); - var tester = new goog.net.NetworkTester(handler.callback, handler); - var orgGetNavigatorOffline = goog.net.NetworkTester.getNavigatorOffline_; - goog.net.NetworkTester.getNavigatorOffline_ = function() { - return true; - }; - try { - assertFalse(tester.isRunning()); - tester.start(); - assertTrue(handler.isEmpty()); - assertTrue(tester.isRunning()); - - // the call is done async - clock.tick(1); - - assertFalse(handler.dequeue()); - assertFalse(tester.isRunning()); - } finally { - // Clean up! - goog.net.NetworkTester.getNavigatorOffline_ = orgGetNavigatorOffline; - } - } - - // Handler object for verifying callback - function Handler() { - this.events_ = []; - }; - - Handler.prototype.callback = function(result) { - this.events_.push(result); - }; - - Handler.prototype.isEmpty = function() { - return this.events_.length == 0; - } - - Handler.prototype.dequeue = function() { - if (this.isEmpty()) { - throw Error("Handler is empty"); - } - return this.events_.shift(); - }; - - // override image constructor for test - can't use a real image due to - // async load of images - have to simulate it - function Image() { - } - - -</script> - -</body> -</html> diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/tmpnetwork.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/tmpnetwork.js.svn-base deleted file mode 100644 index 6f9c03c..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/tmpnetwork.js.svn-base +++ /dev/null @@ -1,153 +0,0 @@ -// Copyright 2006 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview tmpnetwork.js contains some temporary networking functions - * for browserchannel which will be moved at a later date. - */ - - -/** - * Namespace for BrowserChannel - */ -goog.provide('goog.net.tmpnetwork'); - -goog.require('goog.Uri'); -goog.require('goog.net.ChannelDebug'); - - -/** - * Default timeout to allow for google.com pings. - * @type {number} - */ -goog.net.tmpnetwork.GOOGLECOM_TIMEOUT = 10000; - - -goog.net.tmpnetwork.testGoogleCom = function(callback, opt_imageUri) { - // We need to add a 'rand' to make sure the response is not fulfilled - // by browser cache. - var uri = opt_imageUri; - if (!uri) { - uri = new goog.Uri('//www.google.com/images/cleardot.gif'); - uri.makeUnique(); - } - goog.net.tmpnetwork.testLoadImage(uri.toString(), - goog.net.tmpnetwork.GOOGLECOM_TIMEOUT, callback); -}; - - -/** - * Test loading the given image, retrying if necessary. - * @param {string} url URL to the iamge. - * @param {number} timeout Milliseconds before giving up. - * @param {Function} callback Function to call with results. - * @param {number} retries The number of times to retry. - * @param {number=} opt_pauseBetweenRetriesMS Optional number of milliseconds - * between retries - defaults to 0. - */ -goog.net.tmpnetwork.testLoadImageWithRetries = function(url, timeout, callback, - retries, opt_pauseBetweenRetriesMS) { - var channelDebug = new goog.net.ChannelDebug(); - channelDebug.debug('TestLoadImageWithRetries: ' + opt_pauseBetweenRetriesMS); - if (retries == 0) { - // no more retries, give up - callback(false); - return; - } - - var pauseBetweenRetries = opt_pauseBetweenRetriesMS || 0; - retries--; - goog.net.tmpnetwork.testLoadImage(url, timeout, function(succeeded) { - if (succeeded) { - callback(true); - } else { - // try again - goog.global.setTimeout(function() { - goog.net.tmpnetwork.testLoadImageWithRetries(url, timeout, callback, - retries, pauseBetweenRetries); - }, pauseBetweenRetries); - } - }); -}; - - -/** - * Test loading the given image. - * @param {string} url URL to the iamge. - * @param {number} timeout Milliseconds before giving up. - * @param {Function} callback Function to call with results. - */ -goog.net.tmpnetwork.testLoadImage = function(url, timeout, callback) { - var channelDebug = new goog.net.ChannelDebug(); - channelDebug.debug('TestLoadImage: loading ' + url); - var img = new Image(); - img.onload = function() { - try { - channelDebug.debug('TestLoadImage: loaded'); - goog.net.tmpnetwork.clearImageCallbacks_(img); - callback(true); - } catch (e) { - channelDebug.dumpException(e); - } - }; - img.onerror = function() { - try { - channelDebug.debug('TestLoadImage: error'); - goog.net.tmpnetwork.clearImageCallbacks_(img); - callback(false); - } catch (e) { - channelDebug.dumpException(e); - } - }; - img.onabort = function() { - try { - channelDebug.debug('TestLoadImage: abort'); - goog.net.tmpnetwork.clearImageCallbacks_(img); - callback(false); - } catch (e) { - channelDebug.dumpException(e); - } - }; - img.ontimeout = function() { - try { - channelDebug.debug('TestLoadImage: timeout'); - goog.net.tmpnetwork.clearImageCallbacks_(img); - callback(false); - } catch (e) { - channelDebug.dumpException(e); - } - }; - - goog.global.setTimeout(function() { - if (img.ontimeout) { - img.ontimeout(); - } - }, timeout); - img.src = url; -}; - - -/** - * Clear handlers to avoid memory leaks. - * @param {Image} img The image to clear handlers from. - * @private - */ -goog.net.tmpnetwork.clearImageCallbacks_ = function(img) { - // NOTE(user): Nullified individually to avoid compiler warnings - // (BUG 658126) - img.onload = null; - img.onerror = null; - img.onabort = null; - img.ontimeout = null; -}; diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/websocket.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/websocket.js.svn-base deleted file mode 100644 index 85b7e0a..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/websocket.js.svn-base +++ /dev/null @@ -1,504 +0,0 @@ -// Copyright 2011 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Definition of the WebSocket class. A WebSocket provides a - * bi-directional, full-duplex communications channel, over a single TCP socket. - * - * See http://dev.w3.org/html5/websockets/ - * for the full HTML5 WebSocket API. - * - * Typical usage will look like this: - * - * var ws = new goog.net.WebSocket(); - * - * var handler = new goog.events.EventHandler(); - * handler.listen(ws, goog.net.WebSocket.EventType.OPENED, onOpen); - * handler.listen(ws, goog.net.WebSocket.EventType.MESSAGE, onMessage); - * - * try { - * ws.open('ws://127.0.0.1:4200'); - * } catch (e) { - * ... - * } - * - */ - -goog.provide('goog.net.WebSocket'); -goog.provide('goog.net.WebSocket.ErrorEvent'); -goog.provide('goog.net.WebSocket.EventType'); -goog.provide('goog.net.WebSocket.MessageEvent'); - -goog.require('goog.Timer'); -goog.require('goog.asserts'); -goog.require('goog.debug.Logger'); -goog.require('goog.debug.entryPointRegistry'); -goog.require('goog.events'); -goog.require('goog.events.Event'); -goog.require('goog.events.EventTarget'); - - - -/** - * Class encapsulating the logic for using a WebSocket. - * - * @param {boolean=} opt_autoReconnect True if the web socket should - * automatically reconnect or not. This is true by default. - * @param {function(number):number=} opt_getNextReconnect A function for - * obtaining the time until the next reconnect attempt. Given the reconnect - * attempt count (which is a positive integer), the function should return a - * positive integer representing the milliseconds to the next reconnect - * attempt. The default function used is an exponential back-off. Note that - * this function is never called if auto reconnect is disabled. - * @constructor - * @extends {goog.events.EventTarget} - */ -goog.net.WebSocket = function(opt_autoReconnect, opt_getNextReconnect) { - goog.base(this); - - /** - * True if the web socket should automatically reconnect or not. - * @type {boolean} - * @private - */ - this.autoReconnect_ = goog.isDef(opt_autoReconnect) ? - opt_autoReconnect : true; - - /** - * A function for obtaining the time until the next reconnect attempt. - * Given the reconnect attempt count (which is a positive integer), the - * function should return a positive integer representing the milliseconds to - * the next reconnect attempt. - * @type {function(number):number} - * @private - */ - this.getNextReconnect_ = opt_getNextReconnect || - goog.net.WebSocket.EXPONENTIAL_BACKOFF_; - - /** - * The time, in milliseconds, that must elapse before the next attempt to - * reconnect. - * @type {number} - * @private - */ - this.nextReconnect_ = this.getNextReconnect_(this.reconnectAttempt_); -}; -goog.inherits(goog.net.WebSocket, goog.events.EventTarget); - - -/** - * The actual web socket that will be used to send/receive messages. - * @type {WebSocket} - * @private - */ -goog.net.WebSocket.prototype.webSocket_ = null; - - -/** - * The URL to which the web socket will connect. - * @type {?string} - * @private - */ -goog.net.WebSocket.prototype.url_ = null; - - -/** - * The subprotocol name used when establishing the web socket connection. - * @type {string|undefined} - * @private - */ -goog.net.WebSocket.prototype.protocol_ = undefined; - - -/** - * True if a call to the close callback is expected or not. - * @type {boolean} - * @private - */ -goog.net.WebSocket.prototype.closeExpected_ = false; - - -/** - * Keeps track of the number of reconnect attempts made since the last - * successful connection. - * @type {number} - * @private - */ -goog.net.WebSocket.prototype.reconnectAttempt_ = 0; - - -/** - * The logger for this class. - * @type {goog.debug.Logger} - * @private - */ -goog.net.WebSocket.prototype.logger_ = goog.debug.Logger.getLogger( - 'goog.net.WebSocket'); - - -/** - * The events fired by the web socket. - * @enum {string} The event types for the web socket. - */ -goog.net.WebSocket.EventType = { - - /** - * Fired when an attempt to open the WebSocket fails or there is a connection - * failure after a successful connection has been established. - */ - CLOSED: goog.events.getUniqueId('closed'), - - /** - * Fired when the WebSocket encounters an error. - */ - ERROR: goog.events.getUniqueId('error'), - - /** - * Fired when a new message arrives from the WebSocket. - */ - MESSAGE: goog.events.getUniqueId('message'), - - /** - * Fired when the WebSocket connection has been established. - */ - OPENED: goog.events.getUniqueId('opened') -}; - - -/** - * The various states of the web socket. - * @enum {number} The states of the web socket. - * @private - */ -goog.net.WebSocket.ReadyState_ = { - // This is the initial state during construction. - CONNECTING: 0, - // This is when the socket is actually open and ready for data. - OPEN: 1, - // This is when the socket is in the middle of a close handshake. - // Note that this is a valid state even if the OPEN state was never achieved. - CLOSING: 2, - // This is when the socket is actually closed. - CLOSED: 3 -}; - - -/** - * The maximum amount of time between reconnect attempts for the exponential - * back-off in milliseconds. - * @type {number} - * @private - */ -goog.net.WebSocket.EXPONENTIAL_BACKOFF_CEILING_ = 60 * 1000; - - -/** - * Computes the next reconnect time given the number of reconnect attempts since - * the last successful connection. - * - * @param {number} attempt The number of reconnect attempts since the last - * connection. - * @return {number} The time, in milliseconds, until the next reconnect attempt. - * @const - * @private - */ -goog.net.WebSocket.EXPONENTIAL_BACKOFF_ = function(attempt) { - var time = Math.pow(2, attempt) * 1000; - return Math.min(time, goog.net.WebSocket.EXPONENTIAL_BACKOFF_CEILING_); -}; - - -/** - * Installs exception protection for all entry points introduced by - * goog.net.WebSocket instances which are not protected by - * {@link goog.debug.ErrorHandler#protectWindowSetTimeout}, - * {@link goog.debug.ErrorHandler#protectWindowSetInterval}, or - * {@link goog.events.protectBrowserEventEntryPoint}. - * - * @param {!goog.debug.ErrorHandler} errorHandler Error handler with which to - * protect the entry points. - */ -goog.net.WebSocket.protectEntryPoints = function(errorHandler) { - goog.net.WebSocket.prototype.onOpen_ = errorHandler.protectEntryPoint( - goog.net.WebSocket.prototype.onOpen_); - goog.net.WebSocket.prototype.onClose_ = errorHandler.protectEntryPoint( - goog.net.WebSocket.prototype.onClose_); - goog.net.WebSocket.prototype.onMessage_ = errorHandler.protectEntryPoint( - goog.net.WebSocket.prototype.onMessage_); - goog.net.WebSocket.prototype.onError_ = errorHandler.protectEntryPoint( - goog.net.WebSocket.prototype.onError_); -}; - - -/** - * Creates and opens the actual WebSocket. Only call this after attaching the - * appropriate listeners to this object. If listeners aren't registered, then - * the {@code goog.net.WebSocket.EventType.OPENED} event might be missed. - * - * @param {string} url The URL to which to connect. - * @param {string=} opt_protocol The subprotocol to use. The connection will - * only be established if the server reports that it has selected this - * subprotocol. The subprotocol name must all be a non-empty ASCII string - * with no control characters and no spaces in them (i.e. only characters - * in the range U+0021 to U+007E). - */ -goog.net.WebSocket.prototype.open = function(url, opt_protocol) { - // Sanity check. This works only in modern browsers. - goog.asserts.assert(goog.global['WebSocket'], - 'This browser does not support WebSocket'); - - // Don't do anything if the web socket is already open. - goog.asserts.assert(!this.isOpen(), 'The WebSocket is already open'); - - // Clear any pending attempts to reconnect. - this.clearReconnectTimer_(); - - // Construct the web socket. - this.url_ = url; - this.protocol_ = opt_protocol; - - // This check has to be made otherwise you get protocol mismatch exceptions - // for passing undefined, null, '', or []. - if (this.protocol_) { - this.logger_.info('Opening the WebSocket on ' + this.url_ + - ' with protocol ' + this.protocol_); - this.webSocket_ = new WebSocket(this.url_, this.protocol_); - } else { - this.logger_.info('Opening the WebSocket on ' + this.url_); - this.webSocket_ = new WebSocket(this.url_); - } - - // Register the event handlers. Note that it is not possible for these - // callbacks to be missed because it is registered after the web socket is - // instantiated. Because of the synchronous nature of JavaScript, this code - // will execute before the browser creates the resource and makes any calls - // to these callbacks. - this.webSocket_.onopen = goog.bind(this.onOpen_, this); - this.webSocket_.onclose = goog.bind(this.onClose_, this); - this.webSocket_.onmessage = goog.bind(this.onMessage_, this); - this.webSocket_.onerror = goog.bind(this.onError_, this); -}; - - -/** - * Closes the web socket connection. - */ -goog.net.WebSocket.prototype.close = function() { - - // Clear any pending attempts to reconnect. - this.clearReconnectTimer_(); - - // Attempt to close only if the web socket was created. - if (this.webSocket_) { - this.logger_.info('Closing the WebSocket.'); - - // Close is expected here since it was a direct call. Close is considered - // unexpected when opening the connection fails or there is some other form - // of connection loss after being connected. - this.closeExpected_ = true; - this.webSocket_.close(); - this.webSocket_ = null; - } -}; - - -/** - * Sends the message over the web socket. - * - * @param {string} message The message to send. - */ -goog.net.WebSocket.prototype.send = function(message) { - // Make sure the socket is ready to go before sending a message. - goog.asserts.assert(this.isOpen(), 'Cannot send without an open socket'); - - // Send the message and let onError_ be called if it fails thereafter. - this.webSocket_.send(message); -}; - - -/** - * Checks to see if the web socket is open or not. - * - * @return {boolean} True if the web socket is open, false otherwise. - */ -goog.net.WebSocket.prototype.isOpen = function() { - return !!this.webSocket_ && - this.webSocket_.readyState == goog.net.WebSocket.ReadyState_.OPEN; -}; - - -/** - * Called when the web socket has connected. - * - * @private - */ -goog.net.WebSocket.prototype.onOpen_ = function() { - this.logger_.info('WebSocket opened on ' + this.url_); - this.dispatchEvent(goog.net.WebSocket.EventType.OPENED); - - // Set the next reconnect interval. - this.reconnectAttempt_ = 0; - this.nextReconnect_ = this.getNextReconnect_(this.reconnectAttempt_); -}; - - -/** - * Called when the web socket has closed. - * - * @param {!Event} event The close event. - * @private - */ -goog.net.WebSocket.prototype.onClose_ = function(event) { - this.logger_.info('The WebSocket on ' + this.url_ + ' closed.'); - - // Firing this event allows handlers to query the URL. - this.dispatchEvent(goog.net.WebSocket.EventType.CLOSED); - - // Always clear out the web socket on a close event. - this.webSocket_ = null; - - // See if this is an expected call to onClose_. - if (this.closeExpected_) { - this.logger_.info('The WebSocket closed normally.'); - // Only clear out the URL if this is a normal close. - this.url_ = null; - this.protocol_ = undefined; - } else { - // Unexpected, so try to reconnect. - this.logger_.severe('The WebSocket disconnected unexpectedly: ' + - event.data); - - // Only try to reconnect if it is enabled. - if (this.autoReconnect_) { - // Log the reconnect attempt. - var seconds = Math.floor(this.nextReconnect_ / 1000); - this.logger_.info('Seconds until next reconnect attempt: ' + seconds); - - // Actually schedule the timer. - this.reconnectTimer_ = goog.Timer.callOnce( - goog.bind(this.open, this, this.url_, this.protocol_), - this.nextReconnect_, this); - - // Set the next reconnect interval. - this.reconnectAttempt_++; - this.nextReconnect_ = this.getNextReconnect_(this.reconnectAttempt_); - } - } - this.closeExpected_ = false; -}; - - -/** - * Called when a new message arrives from the server. - * - * @param {MessageEvent} event The web socket message event. - * @private - */ -goog.net.WebSocket.prototype.onMessage_ = function(event) { - var message = /** @type {string} */ (event.data); - this.dispatchEvent(new goog.net.WebSocket.MessageEvent(message)); -}; - - -/** - * Called when there is any error in communication. - * - * @param {Event} event The error event containing the error data. - * @private - */ -goog.net.WebSocket.prototype.onError_ = function(event) { - var data = /** @type {string} */ event.data; - this.logger_.severe('An error occurred: ' + data); - this.dispatchEvent(new goog.net.WebSocket.ErrorEvent(data)); -}; - - -/** - * Clears the reconnect timer. - * - * @private - */ -goog.net.WebSocket.prototype.clearReconnectTimer_ = function() { - if (goog.isDefAndNotNull(this.reconnectTimer_)) { - goog.Timer.clear(this.reconnectTimer_); - } - this.reconnectTimer_ = null; -}; - - -/** @override */ -goog.net.WebSocket.prototype.disposeInternal = function() { - goog.base(this, 'disposeInternal'); - this.close(); -}; - - - -/** - * Object representing a new incoming message event. - * - * @param {string} message The raw message coming from the web socket. - * @extends {goog.events.Event} - * @constructor - */ -goog.net.WebSocket.MessageEvent = function(message) { - goog.base(this, goog.net.WebSocket.EventType.MESSAGE); - - /** - * The new message from the web socket. - * @type {string} - */ - this.message = message; -}; -goog.inherits(goog.net.WebSocket.MessageEvent, goog.events.Event); - - - -/** - * Object representing an error event. This is fired whenever an error occurs - * on the web socket. - * - * @param {string} data The error data. - * @extends {goog.events.Event} - * @constructor - */ -goog.net.WebSocket.ErrorEvent = function(data) { - goog.base(this, goog.net.WebSocket.EventType.ERROR); - - /** - * The error data coming from the web socket. - * @type {string} - */ - this.data = data; -}; -goog.inherits(goog.net.WebSocket.ErrorEvent, goog.events.Event); - - -// Register the WebSocket as an entry point, so that it can be monitored for -// exception handling, etc. -goog.debug.entryPointRegistry.register( - /** - * @param {function(!Function): !Function} transformer The transforming - * function. - */ - function(transformer) { - goog.net.WebSocket.prototype.onOpen_ = - transformer(goog.net.WebSocket.prototype.onOpen_); - goog.net.WebSocket.prototype.onClose_ = - transformer(goog.net.WebSocket.prototype.onClose_); - goog.net.WebSocket.prototype.onMessage_ = - transformer(goog.net.WebSocket.prototype.onMessage_); - goog.net.WebSocket.prototype.onError_ = - transformer(goog.net.WebSocket.prototype.onError_); - }); diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/websocket_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/websocket_test.html.svn-base deleted file mode 100644 index 4901830..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/websocket_test.html.svn-base +++ /dev/null @@ -1,367 +0,0 @@ -<!DOCTYPE html> -<html> -<!-- -Copyright 2011 The Closure Library Authors. All Rights Reserved. - -Use of this source code is governed by the Apache License, Version 2.0. -See the COPYING file for details. ---> -<!-- ---> -<head> -<meta http-equiv="X-UA-Compatible" content="IE=edge"> -<title>Closure Unit Tests - goog.net.WebSocket</title> -<script type="text/javascript" src="../base.js"></script> -<script type="text/javascript"> - goog.require('goog.debug.EntryPointMonitor'); - goog.require('goog.debug.ErrorHandler'); - goog.require('goog.debug.entryPointRegistry'); - goog.require('goog.events'); - goog.require('goog.functions'); - goog.require('goog.net.WebSocket'); - goog.require('goog.net.WebSocket.EventType'); - goog.require('goog.testing.MockClock'); - goog.require('goog.testing.PropertyReplacer'); - goog.require('goog.testing.jsunit'); - goog.require('goog.testing.recordFunction'); -</script> -</head> -<body> - -<!-- Define unit tests. --> -<script type="text/javascript" > - -var webSocket; -var mockClock; -var pr; -var testUrl; - -var originalOnOpen = goog.net.WebSocket.prototype.onOpen_; -var originalOnClose = goog.net.WebSocket.prototype.onClose_; -var originalOnMessage = goog.net.WebSocket.prototype.onMessage_; -var originalOnError = goog.net.WebSocket.prototype.onError_; - -function setUp() { - pr = new goog.testing.PropertyReplacer(); - pr.set(goog.global, 'WebSocket', MockWebSocket); - mockClock = new goog.testing.MockClock(true); - testUrl = 'ws://127.0.0.1:4200'; - testProtocol = 'xmpp'; -} - -function tearDown() { - pr.reset(); - goog.net.WebSocket.prototype.onOpen_ = originalOnOpen; - goog.net.WebSocket.prototype.onClose_ = originalOnClose; - goog.net.WebSocket.prototype.onMessage_ = originalOnMessage; - goog.net.WebSocket.prototype.onError_ = originalOnError; - goog.dispose(mockClock); - goog.dispose(webSocket); -} - -function testOpenInUnsupportingBrowserThrowsException() { - // Null out WebSocket to simulate lack of support. - if (goog.global.WebSocket) { - goog.global.WebSocket = null; - } - - webSocket = new goog.net.WebSocket(); - assertThrows('Open should fail if WebSocket is not defined.', - function() { - webSocket.open(testUrl); - }); -} - -function testOpenTwiceThrowsException() { - webSocket = new goog.net.WebSocket(); - webSocket.open(testUrl); - simulateOpenEvent(webSocket.webSocket_); - - assertThrows('Attempting to open a second time should fail.', - function() { - webSocket.open(testUrl); - }); -} - -function testSendWithoutOpeningThrowsException() { - webSocket = new goog.net.WebSocket(); - - assertThrows('Send should fail if the web socket was not first opened.', - function() { - webSocket.send('test message'); - }); -} - -function testOpenWithProtocol() { - webSocket = new goog.net.WebSocket(); - webSocket.open(testUrl, testProtocol); - var ws = webSocket.webSocket_; - simulateOpenEvent(ws); - assertEquals(testUrl, ws.url); - assertEquals(testProtocol, ws.protocol); -} - -function testOpenAndClose() { - webSocket = new goog.net.WebSocket(); - assertFalse(webSocket.isOpen()); - webSocket.open(testUrl); - var ws = webSocket.webSocket_; - simulateOpenEvent(ws); - assertTrue(webSocket.isOpen()); - assertEquals(testUrl, ws.url); - webSocket.close(); - simulateCloseEvent(ws); - assertFalse(webSocket.isOpen()); -} - -function testReconnectionDisabled() { - // Construct the web socket and disable reconnection. - webSocket = new goog.net.WebSocket(false); - - // Record how many times open is called. - pr.set(webSocket, 'open', goog.testing.recordFunction(webSocket.open)); - - // Open the web socket. - webSocket.open(testUrl); - assertEquals(0, webSocket.reconnectAttempt_); - assertEquals(1, webSocket.open.getCallCount()); - assertFalse(webSocket.isOpen()); - - // Simulate failure. - var ws = webSocket.webSocket_; - simulateCloseEvent(ws); - assertFalse(webSocket.isOpen()); - assertEquals(0, webSocket.reconnectAttempt_); - assertEquals(1, webSocket.open.getCallCount()); - - // Make sure a reconnection doesn't happen. - mockClock.tick(100000); - assertEquals(0, webSocket.reconnectAttempt_); - assertEquals(1, webSocket.open.getCallCount()); -} - -function testReconnectionWithFailureOnFirstOpen() { - // Construct the web socket with a linear back-off. - webSocket = new goog.net.WebSocket(true, linearBackOff); - - // Record how many times open is called. - pr.set(webSocket, 'open', goog.testing.recordFunction(webSocket.open)); - - // Open the web socket. - webSocket.open(testUrl, testProtocol); - assertEquals(0, webSocket.reconnectAttempt_); - assertEquals(1, webSocket.open.getCallCount()); - assertFalse(webSocket.isOpen()); - - // Simulate failure. - var ws = webSocket.webSocket_; - simulateCloseEvent(ws); - assertFalse(webSocket.isOpen()); - assertEquals(1, webSocket.reconnectAttempt_); - assertEquals(1, webSocket.open.getCallCount()); - - // Make sure the reconnect doesn't happen before it should. - mockClock.tick(linearBackOff(0) - 1); - assertEquals(1, webSocket.open.getCallCount()); - mockClock.tick(1); - assertEquals(2, webSocket.open.getCallCount()); - - // Simulate another failure. - simulateCloseEvent(ws); - assertFalse(webSocket.isOpen()); - assertEquals(2, webSocket.reconnectAttempt_); - assertEquals(2, webSocket.open.getCallCount()); - - // Make sure the reconnect doesn't happen before it should. - mockClock.tick(linearBackOff(1) - 1); - assertEquals(2, webSocket.open.getCallCount()); - mockClock.tick(1); - assertEquals(3, webSocket.open.getCallCount()); - - // Simulate connection success. - simulateOpenEvent(ws); - assertEquals(0, webSocket.reconnectAttempt_); - assertEquals(3, webSocket.open.getCallCount()); - - // Make sure the reconnection has the same url and protocol. - assertEquals(testUrl, ws.url); - assertEquals(testProtocol, ws.protocol); - - // Ensure no further calls to open are made. - mockClock.tick(linearBackOff(10)); - assertEquals(3, webSocket.open.getCallCount()); -} - -function testReconnectionWithFailureAfterOpen() { - // Construct the web socket with a linear back-off. - webSocket = new goog.net.WebSocket(true, fibonacciBackOff); - - // Record how many times open is called. - pr.set(webSocket, 'open', goog.testing.recordFunction(webSocket.open)); - - // Open the web socket. - webSocket.open(testUrl); - assertEquals(0, webSocket.reconnectAttempt_); - assertEquals(1, webSocket.open.getCallCount()); - assertFalse(webSocket.isOpen()); - - // Simulate connection success. - var ws = webSocket.webSocket_; - simulateOpenEvent(ws); - assertEquals(0, webSocket.reconnectAttempt_); - assertEquals(1, webSocket.open.getCallCount()); - - // Let some time pass, then fail the connection. - mockClock.tick(100000); - simulateCloseEvent(ws); - assertFalse(webSocket.isOpen()); - assertEquals(1, webSocket.reconnectAttempt_); - assertEquals(1, webSocket.open.getCallCount()); - - // Make sure the reconnect doesn't happen before it should. - mockClock.tick(fibonacciBackOff(0) - 1); - assertEquals(1, webSocket.open.getCallCount()); - mockClock.tick(1); - assertEquals(2, webSocket.open.getCallCount()); - - // Simulate connection success. - ws = webSocket.webSocket_; - simulateOpenEvent(ws); - assertEquals(0, webSocket.reconnectAttempt_); - assertEquals(2, webSocket.open.getCallCount()); - - // Ensure no further calls to open are made. - mockClock.tick(fibonacciBackOff(10)); - assertEquals(2, webSocket.open.getCallCount()); -} - -function testExponentialBackOff() { - assertEquals(1000, goog.net.WebSocket.EXPONENTIAL_BACKOFF_(0)); - assertEquals(2000, goog.net.WebSocket.EXPONENTIAL_BACKOFF_(1)); - assertEquals(4000, goog.net.WebSocket.EXPONENTIAL_BACKOFF_(2)); - assertEquals(60000, goog.net.WebSocket.EXPONENTIAL_BACKOFF_(6)); - assertEquals(60000, goog.net.WebSocket.EXPONENTIAL_BACKOFF_(7)); -} - -function testEntryPointRegistry() { - var monitor = new goog.debug.EntryPointMonitor(); - var replacement = function() {}; - monitor.wrap = goog.testing.recordFunction( - goog.functions.constant(replacement)); - - goog.debug.entryPointRegistry.monitorAll(monitor); - assertTrue(monitor.wrap.getCallCount() >= 1); - assertEquals(replacement, goog.net.WebSocket.prototype.onOpen_); - assertEquals(replacement, goog.net.WebSocket.prototype.onClose_); - assertEquals(replacement, goog.net.WebSocket.prototype.onMessage_); - assertEquals(replacement, goog.net.WebSocket.prototype.onError_); -} - -function testErrorHandlerCalled() { - var errorHandlerCalled = false; - var errorHandler = new goog.debug.ErrorHandler(function() { - errorHandlerCalled = true; - }); - goog.net.WebSocket.protectEntryPoints(errorHandler); - - webSocket = new goog.net.WebSocket(); - goog.events.listenOnce(webSocket, goog.net.WebSocket.EventType.OPENED, - function() { - throw Error(); - }); - - webSocket.open(testUrl); - var ws = webSocket.webSocket_; - assertThrows(function() { - simulateOpenEvent(ws); - }); - - assertTrue('Error handler callback should be called when registered as ' + - 'protecting the entry points.', errorHandlerCalled); -} - -/** - * Simulates the browser firing the open event for the given web socket. - * @param {MockWebSocket} ws The mock web socket. - */ -function simulateOpenEvent(ws) { - ws.readyState = goog.net.WebSocket.ReadyState_.OPEN; - ws.onopen(); -} - -/** - * Simulates the browser firing the close event for the given web socket. - * @param {MockWebSocket} ws The mock web socket. - */ -function simulateCloseEvent(ws) { - ws.readyState = goog.net.WebSocket.ReadyState_.CLOSED; - ws.onclose({data: 'mock close event'}); -} - -/** - * Strategy for reconnection that backs off linearly with a 1 second offset. - * @param {number} attempt The number of reconnects since the last connection. - * @return {number} The amount of time to the next reconnect, in milliseconds. - */ -function linearBackOff(attempt) { - return (attempt * 1000) + 1000; -} - -/** - * Strategy for reconnection that backs off with the fibonacci pattern. It is - * offset by 5 seconds so the first attempt will happen after 5 seconds. - * @param {number} attempt The number of reconnects since the last connection. - * @return {number} The amount of time to the next reconnect, in milliseconds. - */ -function fibonacciBackOff(attempt) { - return (fibonacci(attempt) * 1000) + 5000; -} - -/** - * Computes the desired fibonacci number. - * @param {number} n The nth desired fibonacci number. - * @return {number} The nth fibonacci number. - */ -function fibonacci(n) { - if (n == 0) { - return 0; - } else if (n == 1) { - return 1; - } else { - return fibonacci(n - 2) + fibonacci(n - 1); - } -} - - - -/** - * Mock WebSocket constructor. - * @param {string} url The url to the web socket server. - * @param {string} protocol The protocol to use. - * @constructor - */ -MockWebSocket = function(url, protocol) { - this.url = url; - this.protocol = protocol; - this.readyState = goog.net.WebSocket.ReadyState_.CONNECTING; -}; - - -/** - * Mocks out the close method of the WebSocket. - */ -MockWebSocket.prototype.close = function() { - this.readyState = goog.net.WebSocket.ReadyState_.CLOSING; -}; - - -/** - * Mocks out the send method of the WebSocket. - */ -MockWebSocket.prototype.send = function() { - // Nothing to do here. -}; - -</script> -</body> -</html> diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/wrapperxmlhttpfactory.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/wrapperxmlhttpfactory.js.svn-base deleted file mode 100644 index 2a0a159..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/wrapperxmlhttpfactory.js.svn-base +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2010 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Implementation of XmlHttpFactory which allows construction from - * simple factory methods. - * @author dbk@google.com (David Barrett-Kahn) - */ - -goog.provide('goog.net.WrapperXmlHttpFactory'); - -goog.require('goog.net.XmlHttpFactory'); - - - -/** - * An xhr factory subclass which can be constructed using two factory methods. - * This exists partly to allow the preservation of goog.net.XmlHttp.setFactory() - * with an unchanged signature. - * @param {function() : !(XMLHttpRequest|GearsHttpRequest)} xhrFactory A - * function which returns a new XHR object. - * @param {function() : !Object} optionsFactory A function which returns the - * options associated with xhr objects from this factory. - * @extends {goog.net.XmlHttpFactory} - * @constructor - */ -goog.net.WrapperXmlHttpFactory = function(xhrFactory, optionsFactory) { - goog.net.XmlHttpFactory.call(this); - - /** - * XHR factory method. - * @type {function() : !(XMLHttpRequest|GearsHttpRequest)} - * @private - */ - this.xhrFactory_ = xhrFactory; - - /** - * Options factory method. - * @type {function() : !Object} - * @private - */ - this.optionsFactory_ = optionsFactory; -}; -goog.inherits(goog.net.WrapperXmlHttpFactory, goog.net.XmlHttpFactory); - - -/** @override */ -goog.net.WrapperXmlHttpFactory.prototype.createInstance = function() { - return this.xhrFactory_(); -}; - - -/** @override */ -goog.net.WrapperXmlHttpFactory.prototype.getOptions = function() { - return this.optionsFactory_(); -}; - diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/xhrio.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/xhrio.js.svn-base deleted file mode 100644 index 09e30fa..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/xhrio.js.svn-base +++ /dev/null @@ -1,1082 +0,0 @@ -// Copyright 2006 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Wrapper class for handling XmlHttpRequests. - * - * One off requests can be sent through goog.net.XhrIo.send() or an - * instance can be created to send multiple requests. Each request uses its - * own XmlHttpRequest object and handles clearing of the event callback to - * ensure no leaks. - * - * XhrIo is event based, it dispatches events when a request finishes, fails or - * succeeds or when the ready-state changes. The ready-state or timeout event - * fires first, followed by a generic completed event. Then the abort, error, - * or success event is fired as appropriate. Lastly, the ready event will fire - * to indicate that the object may be used to make another request. - * - * The error event may also be called before completed and - * ready-state-change if the XmlHttpRequest.open() or .send() methods throw. - * - * This class does not support multiple requests, queuing, or prioritization. - * - * Tested = IE6, FF1.5, Safari, Opera 8.5 - * - * TODO(user): Error cases aren't playing nicely in Safari. - * - */ - - -goog.provide('goog.net.XhrIo'); -goog.provide('goog.net.XhrIo.ResponseType'); - -goog.require('goog.Timer'); -goog.require('goog.debug.Logger'); -goog.require('goog.debug.entryPointRegistry'); -goog.require('goog.debug.errorHandlerWeakDep'); -goog.require('goog.events.EventTarget'); -goog.require('goog.json'); -goog.require('goog.net.ErrorCode'); -goog.require('goog.net.EventType'); -goog.require('goog.net.HttpStatus'); -goog.require('goog.net.XmlHttp'); -goog.require('goog.object'); -goog.require('goog.structs'); -goog.require('goog.structs.Map'); -goog.require('goog.uri.utils'); - - - -/** - * Basic class for handling XMLHttpRequests. - * @param {goog.net.XmlHttpFactory=} opt_xmlHttpFactory Factory to use when - * creating XMLHttpRequest objects. - * @constructor - * @extends {goog.events.EventTarget} - */ -goog.net.XhrIo = function(opt_xmlHttpFactory) { - goog.events.EventTarget.call(this); - - /** - * Map of default headers to add to every request, use: - * XhrIo.headers.set(name, value) - * @type {goog.structs.Map} - */ - this.headers = new goog.structs.Map(); - - /** - * Optional XmlHttpFactory - * @type {goog.net.XmlHttpFactory} - * @private - */ - this.xmlHttpFactory_ = opt_xmlHttpFactory || null; -}; -goog.inherits(goog.net.XhrIo, goog.events.EventTarget); - - -/** - * Response types that may be requested for XMLHttpRequests. - * @enum {string} - * @see http://dev.w3.org/2006/webapi/XMLHttpRequest-2/#the-responsetype-attribute - */ -goog.net.XhrIo.ResponseType = { - DEFAULT: '', - TEXT: 'text', - DOCUMENT: 'document', - // Not supported as of Chrome 10.0.612.1 dev - BLOB: 'blob', - ARRAY_BUFFER: 'arraybuffer' -}; - - -/** - * A reference to the XhrIo logger - * @type {goog.debug.Logger} - * @private - */ -goog.net.XhrIo.prototype.logger_ = - goog.debug.Logger.getLogger('goog.net.XhrIo'); - - -/** - * The Content-Type HTTP header name - * @type {string} - */ -goog.net.XhrIo.CONTENT_TYPE_HEADER = 'Content-Type'; - - -/** - * The pattern matching the 'http' and 'https' URI schemes - * @type {!RegExp} - */ -goog.net.XhrIo.HTTP_SCHEME_PATTERN = /^https?$/i; - - -/** - * The Content-Type HTTP header value for a url-encoded form - * @type {string} - */ -goog.net.XhrIo.FORM_CONTENT_TYPE = - 'application/x-www-form-urlencoded;charset=utf-8'; - - -/** - * All non-disposed instances of goog.net.XhrIo created - * by {@link goog.net.XhrIo.send} are in this Array. - * @see goog.net.XhrIo.cleanup - * @type {Array.<goog.net.XhrIo>} - * @private - */ -goog.net.XhrIo.sendInstances_ = []; - - -/** - * Static send that creates a short lived instance of XhrIo to send the - * request. - * @see goog.net.XhrIo.cleanup - * @param {string|goog.Uri} url Uri to make request to. - * @param {Function=} opt_callback Callback function for when request is - * complete. - * @param {string=} opt_method Send method, default: GET. - * @param {string|GearsBlob=} opt_content Post data. This can be a Gears blob - * if the underlying HTTP request object is a Gears HTTP request. - * @param {Object|goog.structs.Map=} opt_headers Map of headers to add to the - * request. - * @param {number=} opt_timeoutInterval Number of milliseconds after which an - * incomplete request will be aborted; 0 means no timeout is set. - */ -goog.net.XhrIo.send = function(url, opt_callback, opt_method, opt_content, - opt_headers, opt_timeoutInterval) { - var x = new goog.net.XhrIo(); - goog.net.XhrIo.sendInstances_.push(x); - if (opt_callback) { - goog.events.listen(x, goog.net.EventType.COMPLETE, opt_callback); - } - goog.events.listen(x, - goog.net.EventType.READY, - goog.partial(goog.net.XhrIo.cleanupSend_, x)); - if (opt_timeoutInterval) { - x.setTimeoutInterval(opt_timeoutInterval); - } - x.send(url, opt_method, opt_content, opt_headers); -}; - - -/** - * Disposes all non-disposed instances of goog.net.XhrIo created by - * {@link goog.net.XhrIo.send}. - * {@link goog.net.XhrIo.send} cleans up the goog.net.XhrIo instance - * it creates when the request completes or fails. However, if - * the request never completes, then the goog.net.XhrIo is not disposed. - * This can occur if the window is unloaded before the request completes. - * We could have {@link goog.net.XhrIo.send} return the goog.net.XhrIo - * it creates and make the client of {@link goog.net.XhrIo.send} be - * responsible for disposing it in this case. However, this makes things - * significantly more complicated for the client, and the whole point - * of {@link goog.net.XhrIo.send} is that it's simple and easy to use. - * Clients of {@link goog.net.XhrIo.send} should call - * {@link goog.net.XhrIo.cleanup} when doing final - * cleanup on window unload. - */ -goog.net.XhrIo.cleanup = function() { - var instances = goog.net.XhrIo.sendInstances_; - while (instances.length) { - instances.pop().dispose(); - } -}; - - -/** - * Installs exception protection for all entry point introduced by - * goog.net.XhrIo instances which are not protected by - * {@link goog.debug.ErrorHandler#protectWindowSetTimeout}, - * {@link goog.debug.ErrorHandler#protectWindowSetInterval}, or - * {@link goog.events.protectBrowserEventEntryPoint}. - * - * @param {goog.debug.ErrorHandler} errorHandler Error handler with which to - * protect the entry point(s). - */ -goog.net.XhrIo.protectEntryPoints = function(errorHandler) { - goog.net.XhrIo.prototype.onReadyStateChangeEntryPoint_ = - errorHandler.protectEntryPoint( - goog.net.XhrIo.prototype.onReadyStateChangeEntryPoint_); -}; - - -/** - * Disposes of the specified goog.net.XhrIo created by - * {@link goog.net.XhrIo.send} and removes it from - * {@link goog.net.XhrIo.pendingStaticSendInstances_}. - * @param {goog.net.XhrIo} XhrIo An XhrIo created by - * {@link goog.net.XhrIo.send}. - * @private - */ -goog.net.XhrIo.cleanupSend_ = function(XhrIo) { - XhrIo.dispose(); - goog.array.remove(goog.net.XhrIo.sendInstances_, XhrIo); -}; - - -/** - * Whether XMLHttpRequest is active. A request is active from the time send() - * is called until onReadyStateChange() is complete, or error() or abort() - * is called. - * @type {boolean} - * @private - */ -goog.net.XhrIo.prototype.active_ = false; - - -/** - * Reference to an XMLHttpRequest object that is being used for the transfer. - * @type {XMLHttpRequest|GearsHttpRequest} - * @private - */ -goog.net.XhrIo.prototype.xhr_ = null; - - -/** - * The options to use with the current XMLHttpRequest object. - * @type {Object} - * @private - */ -goog.net.XhrIo.prototype.xhrOptions_ = null; - - -/** - * Last URL that was requested. - * @type {string|goog.Uri} - * @private - */ -goog.net.XhrIo.prototype.lastUri_ = ''; - - -/** - * Method for the last request. - * @type {string} - * @private - */ -goog.net.XhrIo.prototype.lastMethod_ = ''; - - -/** - * Last error code. - * @type {goog.net.ErrorCode} - * @private - */ -goog.net.XhrIo.prototype.lastErrorCode_ = goog.net.ErrorCode.NO_ERROR; - - -/** - * Last error message. - * @type {Error|string} - * @private - */ -goog.net.XhrIo.prototype.lastError_ = ''; - - -/** - * This is used to ensure that we don't dispatch an multiple ERROR events. This - * can happen in IE when it does a synchronous load and one error is handled in - * the ready statte change and one is handled due to send() throwing an - * exception. - * @type {boolean} - * @private - */ -goog.net.XhrIo.prototype.errorDispatched_ = false; - - -/** - * Used to make sure we don't fire the complete event from inside a send call. - * @type {boolean} - * @private - */ -goog.net.XhrIo.prototype.inSend_ = false; - - -/** - * Used in determining if a call to {@link #onReadyStateChange_} is from within - * a call to this.xhr_.open. - * @type {boolean} - * @private - */ -goog.net.XhrIo.prototype.inOpen_ = false; - - -/** - * Used in determining if a call to {@link #onReadyStateChange_} is from within - * a call to this.xhr_.abort. - * @type {boolean} - * @private - */ -goog.net.XhrIo.prototype.inAbort_ = false; - - -/** - * Number of milliseconds after which an incomplete request will be aborted and - * a {@link goog.net.EventType.TIMEOUT} event raised; 0 means no timeout is set. - * @type {number} - * @private - */ -goog.net.XhrIo.prototype.timeoutInterval_ = 0; - - -/** - * Window timeout ID used to cancel the timeout event handler if the request - * completes successfully. - * @type {Object} - * @private - */ -goog.net.XhrIo.prototype.timeoutId_ = null; - - -/** - * The requested type for the response. The empty string means use the default - * XHR behavior. - * @type {goog.net.XhrIo.ResponseType} - * @private - */ -goog.net.XhrIo.prototype.responseType_ = goog.net.XhrIo.ResponseType.DEFAULT; - - -/** - * Whether a "credentialed" request is to be sent (one that is aware of cookies - * and authentication) . This is applicable only for cross-domain requests and - * more recent browsers that support this part of the HTTP Access Control - * standard. - * - * @see http://dev.w3.org/2006/webapi/XMLHttpRequest-2/#withcredentials - * - * @type {boolean} - * @private - */ -goog.net.XhrIo.prototype.withCredentials_ = false; - - -/** - * Returns the number of milliseconds after which an incomplete request will be - * aborted, or 0 if no timeout is set. - * @return {number} Timeout interval in milliseconds. - */ -goog.net.XhrIo.prototype.getTimeoutInterval = function() { - return this.timeoutInterval_; -}; - - -/** - * Sets the number of milliseconds after which an incomplete request will be - * aborted and a {@link goog.net.EventType.TIMEOUT} event raised; 0 means no - * timeout is set. - * @param {number} ms Timeout interval in milliseconds; 0 means none. - */ -goog.net.XhrIo.prototype.setTimeoutInterval = function(ms) { - this.timeoutInterval_ = Math.max(0, ms); -}; - - -/** - * Sets the desired type for the response. At time of writing, this is only - * supported in very recent versions of WebKit (10.0.612.1 dev and later). - * - * If this is used, the response may only be accessed via {@link #getResponse}. - * - * @param {goog.net.XhrIo.ResponseType} type The desired type for the response. - */ -goog.net.XhrIo.prototype.setResponseType = function(type) { - this.responseType_ = type; -}; - - -/** - * Gets the desired type for the response. - * @return {goog.net.XhrIo.ResponseType} The desired type for the response. - */ -goog.net.XhrIo.prototype.getResponseType = function() { - return this.responseType_; -}; - - -/** - * Sets whether a "credentialed" request that is aware of cookie and - * authentication information should be made. This option is only supported by - * browsers that support HTTP Access Control. As of this writing, this option - * is not supported in IE. - * - * @param {boolean} withCredentials Whether this should be a "credentialed" - * request. - */ -goog.net.XhrIo.prototype.setWithCredentials = function(withCredentials) { - this.withCredentials_ = withCredentials; -}; - - -/** - * Gets whether a "credentialed" request is to be sent. - * @return {boolean} The desired type for the response. - */ -goog.net.XhrIo.prototype.getWithCredentials = function() { - return this.withCredentials_; -}; - - -/** - * Instance send that actually uses XMLHttpRequest to make a server call. - * @param {string|goog.Uri} url Uri to make request to. - * @param {string=} opt_method Send method, default: GET. - * @param {string|GearsBlob=} opt_content Post data. This can be a Gears blob - * if the underlying HTTP request object is a Gears HTTP request. - * @param {Object|goog.structs.Map=} opt_headers Map of headers to add to the - * request. - */ -goog.net.XhrIo.prototype.send = function(url, opt_method, opt_content, - opt_headers) { - if (this.xhr_) { - throw Error('[goog.net.XhrIo] Object is active with another request'); - } - - var method = opt_method ? opt_method.toUpperCase() : 'GET'; - - this.lastUri_ = url; - this.lastError_ = ''; - this.lastErrorCode_ = goog.net.ErrorCode.NO_ERROR; - this.lastMethod_ = method; - this.errorDispatched_ = false; - this.active_ = true; - - // Use the factory to create the XHR object and options - this.xhr_ = this.createXhr(); - this.xhrOptions_ = this.xmlHttpFactory_ ? - this.xmlHttpFactory_.getOptions() : goog.net.XmlHttp.getOptions(); - - // Set up the onreadystatechange callback - this.xhr_.onreadystatechange = goog.bind(this.onReadyStateChange_, this); - - /** - * Try to open the XMLHttpRequest (always async), if an error occurs here it - * is generally permission denied - * @preserveTry - */ - try { - this.logger_.fine(this.formatMsg_('Opening Xhr')); - this.inOpen_ = true; - this.xhr_.open(method, url, true); // Always async! - this.inOpen_ = false; - } catch (err) { - this.logger_.fine(this.formatMsg_('Error opening Xhr: ' + err.message)); - this.error_(goog.net.ErrorCode.EXCEPTION, err); - return; - } - - // We can't use null since this won't allow POSTs to have a content length - // specified which will cause some proxies to return a 411 error. - var content = opt_content || ''; - - var headers = this.headers.clone(); - - // Add headers specific to this request - if (opt_headers) { - goog.structs.forEach(opt_headers, function(value, key) { - headers.set(key, value); - }); - } - - if (method == 'POST' && - !headers.containsKey(goog.net.XhrIo.CONTENT_TYPE_HEADER)) { - // For POST requests, default to the url-encoded form content type. - headers.set(goog.net.XhrIo.CONTENT_TYPE_HEADER, - goog.net.XhrIo.FORM_CONTENT_TYPE); - } - - // Add the headers to the Xhr object - goog.structs.forEach(headers, function(value, key) { - this.xhr_.setRequestHeader(key, value); - }, this); - - if (this.responseType_) { - this.xhr_.responseType = this.responseType_; - } - - if (goog.object.containsKey(this.xhr_, 'withCredentials')) { - this.xhr_.withCredentials = this.withCredentials_; - } - - /** - * Try to send the request, or other wise report an error (404 not found). - * @preserveTry - */ - try { - if (this.timeoutId_) { - // This should never happen, since the if (this.active_) above shouldn't - // let execution reach this point if there is a request in progress... - goog.Timer.defaultTimerObject.clearTimeout(this.timeoutId_); - this.timeoutId_ = null; - } - if (this.timeoutInterval_ > 0) { - this.logger_.fine(this.formatMsg_('Will abort after ' + - this.timeoutInterval_ + 'ms if incomplete')); - this.timeoutId_ = goog.Timer.defaultTimerObject.setTimeout( - goog.bind(this.timeout_, this), this.timeoutInterval_); - } - this.logger_.fine(this.formatMsg_('Sending request')); - this.inSend_ = true; - this.xhr_.send(content); - this.inSend_ = false; - - } catch (err) { - this.logger_.fine(this.formatMsg_('Send error: ' + err.message)); - this.error_(goog.net.ErrorCode.EXCEPTION, err); - } -}; - - -/** - * Creates a new XHR object. - * @return {XMLHttpRequest|GearsHttpRequest} The newly created XHR object. - * @protected - */ -goog.net.XhrIo.prototype.createXhr = function() { - return this.xmlHttpFactory_ ? - this.xmlHttpFactory_.createInstance() : goog.net.XmlHttp(); -}; - - -/** - * The request didn't complete after {@link goog.net.XhrIo#timeoutInterval_} - * milliseconds; raises a {@link goog.net.EventType.TIMEOUT} event and aborts - * the request. - * @private - */ -goog.net.XhrIo.prototype.timeout_ = function() { - if (typeof goog == 'undefined') { - // If goog is undefined then the callback has occurred as the application - // is unloading and will error. Thus we let it silently fail. - } else if (this.xhr_) { - this.lastError_ = 'Timed out after ' + this.timeoutInterval_ + - 'ms, aborting'; - this.lastErrorCode_ = goog.net.ErrorCode.TIMEOUT; - this.logger_.fine(this.formatMsg_(this.lastError_)); - this.dispatchEvent(goog.net.EventType.TIMEOUT); - this.abort(goog.net.ErrorCode.TIMEOUT); - } -}; - - -/** - * Something errorred, so inactivate, fire error callback and clean up - * @param {goog.net.ErrorCode} errorCode The error code. - * @param {Error} err The error object. - * @private - */ -goog.net.XhrIo.prototype.error_ = function(errorCode, err) { - this.active_ = false; - if (this.xhr_) { - this.inAbort_ = true; - this.xhr_.abort(); // Ensures XHR isn't hung (FF) - this.inAbort_ = false; - } - this.lastError_ = err; - this.lastErrorCode_ = errorCode; - this.dispatchErrors_(); - this.cleanUpXhr_(); -}; - - -/** - * Dispatches COMPLETE and ERROR in case of an error. This ensures that we do - * not dispatch multiple error events. - * @private - */ -goog.net.XhrIo.prototype.dispatchErrors_ = function() { - if (!this.errorDispatched_) { - this.errorDispatched_ = true; - this.dispatchEvent(goog.net.EventType.COMPLETE); - this.dispatchEvent(goog.net.EventType.ERROR); - } -}; - - -/** - * Abort the current XMLHttpRequest - * @param {goog.net.ErrorCode=} opt_failureCode Optional error code to use - - * defaults to ABORT. - */ -goog.net.XhrIo.prototype.abort = function(opt_failureCode) { - if (this.xhr_ && this.active_) { - this.logger_.fine(this.formatMsg_('Aborting')); - this.active_ = false; - this.inAbort_ = true; - this.xhr_.abort(); - this.inAbort_ = false; - this.lastErrorCode_ = opt_failureCode || goog.net.ErrorCode.ABORT; - this.dispatchEvent(goog.net.EventType.COMPLETE); - this.dispatchEvent(goog.net.EventType.ABORT); - this.cleanUpXhr_(); - } -}; - - -/** - * Nullifies all callbacks to reduce risks of leaks. - * @override - * @protected - */ -goog.net.XhrIo.prototype.disposeInternal = function() { - if (this.xhr_) { - // We explicitly do not call xhr_.abort() unless active_ is still true. - // This is to avoid unnecessarily aborting a successful request when - // dispose() is called in a callback triggered by a complete response, but - // in which browser cleanup has not yet finished. - // (See http://b/issue?id=1684217.) - if (this.active_) { - this.active_ = false; - this.inAbort_ = true; - this.xhr_.abort(); - this.inAbort_ = false; - } - this.cleanUpXhr_(true); - } - - goog.net.XhrIo.superClass_.disposeInternal.call(this); -}; - - -/** - * Internal handler for the XHR object's readystatechange event. This method - * checks the status and the readystate and fires the correct callbacks. - * If the request has ended, the handlers are cleaned up and the XHR object is - * nullified. - * @private - */ -goog.net.XhrIo.prototype.onReadyStateChange_ = function() { - if (!this.inOpen_ && !this.inSend_ && !this.inAbort_) { - // Were not being called from within a call to this.xhr_.send - // this.xhr_.abort, or this.xhr_.open, so this is an entry point - this.onReadyStateChangeEntryPoint_(); - } else { - this.onReadyStateChangeHelper_(); - } -}; - - -/** - * Used to protect the onreadystatechange handler entry point. Necessary - * as {#onReadyStateChange_} maybe called from within send or abort, this - * method is only called when {#onReadyStateChange_} is called as an - * entry point. - * {@see #protectEntryPoints} - * @private - */ -goog.net.XhrIo.prototype.onReadyStateChangeEntryPoint_ = function() { - this.onReadyStateChangeHelper_(); -}; - - -/** - * Helper for {@link #onReadyStateChange_}. This is used so that - * entry point calls to {@link #onReadyStateChange_} can be routed through - * {@link #onReadyStateChangeEntryPoint_}. - * @private - */ -goog.net.XhrIo.prototype.onReadyStateChangeHelper_ = function() { - if (!this.active_) { - // can get called inside abort call - return; - } - - if (typeof goog == 'undefined') { - // NOTE(user): If goog is undefined then the callback has occurred as the - // application is unloading and will error. Thus we let it silently fail. - - } else if ( - this.xhrOptions_[goog.net.XmlHttp.OptionType.LOCAL_REQUEST_ERROR] && - this.getReadyState() == goog.net.XmlHttp.ReadyState.COMPLETE && - this.getStatus() == 2) { - // NOTE(user): In IE if send() errors on a *local* request the readystate - // is still changed to COMPLETE. We need to ignore it and allow the - // try/catch around send() to pick up the error. - this.logger_.fine(this.formatMsg_( - 'Local request error detected and ignored')); - - } else { - - // In IE when the response has been cached we sometimes get the callback - // from inside the send call and this usually breaks code that assumes that - // XhrIo is asynchronous. If that is the case we delay the callback - // using a timer. - if (this.inSend_ && - this.getReadyState() == goog.net.XmlHttp.ReadyState.COMPLETE) { - goog.Timer.defaultTimerObject.setTimeout( - goog.bind(this.onReadyStateChange_, this), 0); - return; - } - - this.dispatchEvent(goog.net.EventType.READY_STATE_CHANGE); - - // readyState indicates the transfer has finished - if (this.isComplete()) { - this.logger_.fine(this.formatMsg_('Request complete')); - - this.active_ = false; - - // Call the specific callbacks for success or failure. Only call the - // success if the status is 200 (HTTP_OK) or 304 (HTTP_CACHED) - if (this.isSuccess()) { - this.dispatchEvent(goog.net.EventType.COMPLETE); - this.dispatchEvent(goog.net.EventType.SUCCESS); - } else { - this.lastErrorCode_ = goog.net.ErrorCode.HTTP_ERROR; - this.lastError_ = this.getStatusText() + ' [' + this.getStatus() + ']'; - this.dispatchErrors_(); - } - - this.cleanUpXhr_(); - } - } -}; - - -/** - * Remove the listener to protect against leaks, and nullify the XMLHttpRequest - * object. - * @param {boolean=} opt_fromDispose If this is from the dispose (don't want to - * fire any events). - * @private - */ -goog.net.XhrIo.prototype.cleanUpXhr_ = function(opt_fromDispose) { - if (this.xhr_) { - // Save reference so we can mark it as closed after the READY event. The - // READY event may trigger another request, thus we must nullify this.xhr_ - var xhr = this.xhr_; - var clearedOnReadyStateChange = - this.xhrOptions_[goog.net.XmlHttp.OptionType.USE_NULL_FUNCTION] ? - goog.nullFunction : null; - this.xhr_ = null; - this.xhrOptions_ = null; - - if (this.timeoutId_) { - // Cancel any pending timeout event handler. - goog.Timer.defaultTimerObject.clearTimeout(this.timeoutId_); - this.timeoutId_ = null; - } - - if (!opt_fromDispose) { - this.dispatchEvent(goog.net.EventType.READY); - } - - try { - // NOTE(user): Not nullifying in FireFox can still leak if the callbacks - // are defined in the same scope as the instance of XhrIo. But, IE doesn't - // allow you to set the onreadystatechange to NULL so nullFunction is - // used. - xhr.onreadystatechange = clearedOnReadyStateChange; - } catch (e) { - // This seems to occur with a Gears HTTP request. Delayed the setting of - // this onreadystatechange until after READY is sent out and catching the - // error to see if we can track down the problem. - this.logger_.severe('Problem encountered resetting onreadystatechange: ' + - e.message); - } - } -}; - - -/** - * @return {boolean} Whether there is an active request. - */ -goog.net.XhrIo.prototype.isActive = function() { - return !!this.xhr_; -}; - - -/** - * @return {boolean} Whether the request has completed. - */ -goog.net.XhrIo.prototype.isComplete = function() { - return this.getReadyState() == goog.net.XmlHttp.ReadyState.COMPLETE; -}; - - -/** - * @return {boolean} Whether the request completed with a success. - */ -goog.net.XhrIo.prototype.isSuccess = function() { - var status = this.getStatus(); - // A zero status code is considered successful for local files. - return goog.net.HttpStatus.isSuccess(status) || - status === 0 && !this.isLastUriEffectiveSchemeHttp_(); -}; - - -/** - * @return {boolean} whether the effective scheme of the last URI that was - * fetched was 'http' or 'https'. - * @private - */ -goog.net.XhrIo.prototype.isLastUriEffectiveSchemeHttp_ = function() { - var scheme = goog.uri.utils.getEffectiveScheme(String(this.lastUri_)); - return goog.net.XhrIo.HTTP_SCHEME_PATTERN.test(scheme); -}; - - -/** - * Get the readystate from the Xhr object - * Will only return correct result when called from the context of a callback - * @return {goog.net.XmlHttp.ReadyState} goog.net.XmlHttp.ReadyState.*. - */ -goog.net.XhrIo.prototype.getReadyState = function() { - return this.xhr_ ? - /** @type {goog.net.XmlHttp.ReadyState} */ (this.xhr_.readyState) : - goog.net.XmlHttp.ReadyState.UNINITIALIZED; -}; - - -/** - * Get the status from the Xhr object - * Will only return correct result when called from the context of a callback - * @return {number} Http status. - */ -goog.net.XhrIo.prototype.getStatus = function() { - /** - * IE doesn't like you checking status until the readystate is greater than 2 - * (i.e. it is recieving or complete). The try/catch is used for when the - * page is unloading and an ERROR_NOT_AVAILABLE may occur when accessing xhr_. - * @preserveTry - */ - try { - return this.getReadyState() > goog.net.XmlHttp.ReadyState.LOADED ? - this.xhr_.status : -1; - } catch (e) { - this.logger_.warning('Can not get status: ' + e.message); - return -1; - } -}; - - -/** - * Get the status text from the Xhr object - * Will only return correct result when called from the context of a callback - * @return {string} Status text. - */ -goog.net.XhrIo.prototype.getStatusText = function() { - /** - * IE doesn't like you checking status until the readystate is greater than 2 - * (i.e. it is recieving or complete). The try/catch is used for when the - * page is unloading and an ERROR_NOT_AVAILABLE may occur when accessing xhr_. - * @preserveTry - */ - try { - return this.getReadyState() > goog.net.XmlHttp.ReadyState.LOADED ? - this.xhr_.statusText : ''; - } catch (e) { - this.logger_.fine('Can not get status: ' + e.message); - return ''; - } -}; - - -/** - * Get the last Uri that was requested - * @return {string} Last Uri. - */ -goog.net.XhrIo.prototype.getLastUri = function() { - return String(this.lastUri_); -}; - - -/** - * Get the response text from the Xhr object - * Will only return correct result when called from the context of a callback. - * @return {string} Result from the server, or '' if no result available. - */ -goog.net.XhrIo.prototype.getResponseText = function() { - /** @preserveTry */ - try { - return this.xhr_ ? this.xhr_.responseText : ''; - } catch (e) { - // http://www.w3.org/TR/XMLHttpRequest/#the-responsetext-attribute - // states that responseText should return '' (and responseXML null) - // when the state is not LOADING or DONE. Instead, IE and Gears can - // throw unexpected exceptions, eg, when a request is aborted or no - // data is available yet. - this.logger_.fine('Can not get responseText: ' + e.message); - return ''; - } -}; - - -/** - * Get the response XML from the Xhr object - * Will only return correct result when called from the context of a callback. - * @return {Document} The DOM Document representing the XML file, or null - * if no result available. - */ -goog.net.XhrIo.prototype.getResponseXml = function() { - /** @preserveTry */ - try { - return this.xhr_ ? this.xhr_.responseXML : null; - } catch (e) { - this.logger_.fine('Can not get responseXML: ' + e.message); - return null; - } -}; - - -/** - * Get the response and evaluates it as JSON from the Xhr object - * Will only return correct result when called from the context of a callback - * @param {string=} opt_xssiPrefix Optional XSSI prefix string to use for - * stripping of the response before parsing. This needs to be set only if - * your backend server prepends the same prefix string to the JSON response. - * @return {Object|undefined} JavaScript object. - */ -goog.net.XhrIo.prototype.getResponseJson = function(opt_xssiPrefix) { - if (!this.xhr_) { - return undefined; - } - - var responseText = this.xhr_.responseText; - if (opt_xssiPrefix && responseText.indexOf(opt_xssiPrefix) == 0) { - responseText = responseText.substring(opt_xssiPrefix.length); - } - - return goog.json.parse(responseText); -}; - - -/** - * Get the response as the type specificed by {@link #setResponseType}. At time - * of writing, this is only directly supported in very recent versions of WebKit - * (10.0.612.1 dev and later). If the field is not supported directly, we will - * try to emulate it. - * - * Emulating the response means following the rules laid out at - * http://dev.w3.org/2006/webapi/XMLHttpRequest-2/#the-response-attribute. - * - * On browsers with no support for this (Chrome < 10, Firefox < 4, etc), only - * response types of DEFAULT or TEXT may be used, and the response returned will - * be the text response. - * - * On browsers with Mozilla's draft support for array buffers (Firefox 4, 5), - * only response types of DEFAULT, TEXT, and ARRAY_BUFFER may be used, and the - * response returned will be either the text response or the Mozilla - * implementation of the array buffer response. - * - * On browsers will full support, any valid response type supported by the - * browser may be used, and the response provided by the browser will be - * returned. - * - * @return {*} The response. - */ -goog.net.XhrIo.prototype.getResponse = function() { - /** @preserveTry */ - try { - if (!this.xhr_) { - return null; - } - if ('response' in this.xhr_) { - return this.xhr_.response; - } - switch (this.responseType_) { - case goog.net.XhrIo.ResponseType.DEFAULT: - case goog.net.XhrIo.ResponseType.TEXT: - return this.xhr_.responseText; - // DOCUMENT and BLOB don't need to be handled here because they are - // introduced in the same spec that adds the .response field, and would - // have been caught above. - // ARRAY_BUFFER needs an implementation for Firefox 4, where it was - // implemented using a draft spec rather than the final spec. - case goog.net.XhrIo.ResponseType.ARRAY_BUFFER: - if ('mozResponseArrayBuffer' in this.xhr_) { - return this.xhr_.mozResponseArrayBuffer; - } - } - // Fell through to a response type that is not supported on this browser. - this.logger_.severe('Response type ' + this.responseType_ + ' is not ' + - 'supported on this browser'); - return null; - } catch (e) { - this.logger_.fine('Can not get response: ' + e.message); - return null; - } -}; - - -/** - * Get the value of the response-header with the given name from the Xhr object - * Will only return correct result when called from the context of a callback - * and the request has completed - * @param {string} key The name of the response-header to retrieve. - * @return {string|undefined} The value of the response-header named key. - */ -goog.net.XhrIo.prototype.getResponseHeader = function(key) { - return this.xhr_ && this.isComplete() ? - this.xhr_.getResponseHeader(key) : undefined; -}; - - -/** - * Gets the text of all the headers in the response. - * Will only return correct result when called from the context of a callback - * and the request has completed. - * @return {string} The value of the response headers or empty string. - */ -goog.net.XhrIo.prototype.getAllResponseHeaders = function() { - return this.xhr_ && this.isComplete() ? - this.xhr_.getAllResponseHeaders() : ''; -}; - - -/** - * Get the last error message - * @return {goog.net.ErrorCode} Last error code. - */ -goog.net.XhrIo.prototype.getLastErrorCode = function() { - return this.lastErrorCode_; -}; - - -/** - * Get the last error message - * @return {string} Last error message. - */ -goog.net.XhrIo.prototype.getLastError = function() { - return goog.isString(this.lastError_) ? this.lastError_ : - String(this.lastError_); -}; - - -/** - * Adds the last method, status and URI to the message. This is used to add - * this information to the logging calls. - * @param {string} msg The message text that we want to add the extra text to. - * @return {string} The message with the extra text appended. - * @private - */ -goog.net.XhrIo.prototype.formatMsg_ = function(msg) { - return msg + ' [' + this.lastMethod_ + ' ' + this.lastUri_ + ' ' + - this.getStatus() + ']'; -}; - - -// Register the xhr handler as an entry point, so that -// it can be monitored for exception handling, etc. -goog.debug.entryPointRegistry.register( - /** - * @param {function(!Function): !Function} transformer The transforming - * function. - */ - function(transformer) { - goog.net.XhrIo.prototype.onReadyStateChangeEntryPoint_ = - transformer(goog.net.XhrIo.prototype.onReadyStateChangeEntryPoint_); - }); diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/xhrio_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/xhrio_test.html.svn-base deleted file mode 100644 index 096f8f6..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/xhrio_test.html.svn-base +++ /dev/null @@ -1,639 +0,0 @@ -<!DOCTYPE html> -<html> -<!-- -Copyright 2007 The Closure Library Authors. All Rights Reserved. - -Use of this source code is governed by the Apache License, Version 2.0. -See the COPYING file for details. ---> -<!-- - Author: arv@google.com (Erik Arvidsson) ---> -<head> -<meta http-equiv="X-UA-Compatible" content="IE=edge"> -<title>Closure Unit Tests - goog.net.XhrIo</title> -<script src="../base.js"></script> -<script> - goog.require('goog.debug.ErrorHandler'); - goog.require('goog.functions'); - goog.require('goog.net.WrapperXmlHttpFactory'); - goog.require('goog.net.XhrIo'); - goog.require('goog.object'); - goog.require('goog.string'); - goog.require('goog.testing.MockClock'); - goog.require('goog.testing.jsunit'); - goog.require('goog.testing.net.XhrIo'); - goog.require('goog.testing.recordFunction'); - goog.require('goog.Uri'); -</script> -<script> - -function MockXmlHttp() {} - -MockXmlHttp.prototype.readyState = goog.net.XmlHttp.ReadyState.UNINITIALIZED; - -MockXmlHttp.prototype.status = 200; - -MockXmlHttp.syncSend = false; - -MockXmlHttp.prototype.send = function(opt_data) { - this.readyState = goog.net.XmlHttp.ReadyState.UNINITIALIZED; - - if (MockXmlHttp.syncSend) { - this.complete(); - } - -}; - -MockXmlHttp.prototype.complete = function() { - this.readyState = goog.net.XmlHttp.ReadyState.LOADING; - this.onreadystatechange(); - - this.readyState = goog.net.XmlHttp.ReadyState.LOADED; - this.onreadystatechange(); - - this.readyState = goog.net.XmlHttp.ReadyState.INTERACTIVE; - this.onreadystatechange(); - - this.readyState = goog.net.XmlHttp.ReadyState.COMPLETE; - this.onreadystatechange(); -}; - - -MockXmlHttp.prototype.open = function(verb, uri, async) { -}; - -MockXmlHttp.prototype.abort = function() {}; - -MockXmlHttp.prototype.setRequestHeader = function(key, value) {}; - -var lastMockXmlHttp; -goog.net.XmlHttp.setGlobalFactory(new goog.net.WrapperXmlHttpFactory( - function() { - lastMockXmlHttp = new MockXmlHttp(); - return lastMockXmlHttp; - }, - function() { - return {}; - })); - - -var clock; -var originalEntryPoint = - goog.net.XhrIo.prototype.onReadyStateChangeEntryPoint_; - -function setUp() { - lastMockXmlHttp = null; - clock = new goog.testing.MockClock(true); -} - -function tearDown() { - clock.dispose(); - goog.net.XhrIo.prototype.onReadyStateChangeEntryPoint_ = originalEntryPoint; -} - - -function testSyncSend() { - MockXmlHttp.syncSend = true; - var count = 0; - - var x = new goog.net.XhrIo; - goog.events.listen(x, goog.net.EventType.COMPLETE, function(e) { - assertFalse('Should not fire complete from inside send', inSend); - assertTrue('Should be succesful', e.target.isSuccess()); - count++; - - }); - - var inSend = true; - x.send('url'); - inSend = false; - - clock.tick(1); // callOnce(f, 0, ...) - - assertEquals('Complete should have been called once', 1, count); -} - -function testSyncSendFailure() { - MockXmlHttp.syncSend = true; - var count = 0; - - var x = new goog.net.XhrIo; - goog.events.listen(x, goog.net.EventType.COMPLETE, function(e) { - assertFalse('Should not fire complete from inside send', inSend); - assertFalse('Should not be succesful', e.target.isSuccess()); - count++; - }); - - var inSend = true; - x.send('url'); - lastMockXmlHttp.status = 404; - inSend = false; - - clock.tick(1); // callOnce(f, 0, ...) - - assertEquals('Complete should have been called once', 1, count); -} - - -function testSendRelativeZeroStatus() { - MockXmlHttp.syncSend = true; - var count = 0; - - var x = new goog.net.XhrIo; - goog.events.listen(x, goog.net.EventType.COMPLETE, function(e) { - assertFalse('Should not fire complete from inside send', inSend); - assertEquals('Should be the same as ', e.target.isSuccess(), - window.location.href.toLowerCase().indexOf("file:") == 0); - count++; - }); - - var inSend = true; - x.send('relative'); - lastMockXmlHttp.status = 0; - inSend = false; - - clock.tick(1); // callOnce(f, 0, ...) - - assertEquals('Complete should have been called once', 1, count); -} - - -function testSendRelativeUriZeroStatus() { - MockXmlHttp.syncSend = true; - var count = 0; - - var x = new goog.net.XhrIo; - goog.events.listen(x, goog.net.EventType.COMPLETE, function(e) { - assertFalse('Should not fire complete from inside send', inSend); - assertEquals('Should be the same as ', e.target.isSuccess(), - window.location.href.toLowerCase().indexOf("file:") == 0); - count++; - }); - - var inSend = true; - x.send(goog.Uri.parse('relative')); - lastMockXmlHttp.status = 0; - inSend = false; - - clock.tick(1); // callOnce(f, 0, ...) - - assertEquals('Complete should have been called once', 1, count); -} - - -function testSendHttpZeroStatusFailure() { - MockXmlHttp.syncSend = true; - var count = 0; - - var x = new goog.net.XhrIo; - goog.events.listen(x, goog.net.EventType.COMPLETE, function(e) { - assertFalse('Should not fire complete from inside send', inSend); - assertFalse('Should not be succesful', e.target.isSuccess()); - count++; - }); - - var inSend = true; - x.send('http://foo'); - lastMockXmlHttp.status = 0; - inSend = false; - - clock.tick(1); // callOnce(f, 0, ...) - - assertEquals('Complete should have been called once', 1, count); -} - - -function testSendHttpUpperZeroStatusFailure() { - MockXmlHttp.syncSend = true; - var count = 0; - - var x = new goog.net.XhrIo; - goog.events.listen(x, goog.net.EventType.COMPLETE, function(e) { - assertFalse('Should not fire complete from inside send', inSend); - assertFalse('Should not be succesful', e.target.isSuccess()); - count++; - }); - - var inSend = true; - x.send('HTTP://foo'); - lastMockXmlHttp.status = 0; - inSend = false; - - clock.tick(1); // callOnce(f, 0, ...) - - assertEquals('Complete should have been called once', 1, count); -} - - -function testSendHttpUpperUriZeroStatusFailure() { - MockXmlHttp.syncSend = true; - var count = 0; - - var x = new goog.net.XhrIo; - goog.events.listen(x, goog.net.EventType.COMPLETE, function(e) { - assertFalse('Should not fire complete from inside send', inSend); - assertFalse('Should not be succesful', e.target.isSuccess()); - count++; - }); - - var inSend = true; - x.send(goog.Uri.parse('HTTP://foo')); - lastMockXmlHttp.status = 0; - inSend = false; - - clock.tick(1); // callOnce(f, 0, ...) - - assertEquals('Complete should have been called once', 1, count); -} - - -function testSendHttpUriZeroStatusFailure() { - MockXmlHttp.syncSend = true; - var count = 0; - - var x = new goog.net.XhrIo; - goog.events.listen(x, goog.net.EventType.COMPLETE, function(e) { - assertFalse('Should not fire complete from inside send', inSend); - assertFalse('Should not be succesful', e.target.isSuccess()); - count++; - }); - - var inSend = true; - x.send(goog.Uri.parse('http://foo')); - lastMockXmlHttp.status = 0; - inSend = false; - - clock.tick(1); // callOnce(f, 0, ...) - - assertEquals('Complete should have been called once', 1, count); -} - - -function testSendHttpUriZeroStatusFailure() { - MockXmlHttp.syncSend = true; - var count = 0; - - var x = new goog.net.XhrIo; - goog.events.listen(x, goog.net.EventType.COMPLETE, function(e) { - assertFalse('Should not fire complete from inside send', inSend); - assertFalse('Should not be succesful', e.target.isSuccess()); - count++; - }); - - var inSend = true; - x.send(goog.Uri.parse('HTTP://foo')); - lastMockXmlHttp.status = 0; - inSend = false; - - clock.tick(1); // callOnce(f, 0, ...) - - assertEquals('Complete should have been called once', 1, count); -} - - -function testSendHttpsZeroStatusFailure() { - MockXmlHttp.syncSend = true; - var count = 0; - - var x = new goog.net.XhrIo; - goog.events.listen(x, goog.net.EventType.COMPLETE, function(e) { - assertFalse('Should not fire complete from inside send', inSend); - assertFalse('Should not be succesful', e.target.isSuccess()); - count++; - }); - - var inSend = true; - x.send('https://foo'); - lastMockXmlHttp.status = 0; - inSend = false; - - clock.tick(1); // callOnce(f, 0, ...) - - assertEquals('Complete should have been called once', 1, count); -} - - -function testSendFileUpperZeroStatusSuccess() { - MockXmlHttp.syncSend = true; - var count = 0; - - var x = new goog.net.XhrIo; - goog.events.listen(x, goog.net.EventType.COMPLETE, function(e) { - assertFalse('Should not fire complete from inside send', inSend); - assertTrue('Should not be succesful', e.target.isSuccess()); - count++; - }); - - var inSend = true; - x.send('FILE:///foo'); - lastMockXmlHttp.status = 0; - inSend = false; - - clock.tick(1); // callOnce(f, 0, ...) - - assertEquals('Complete should have been called once', 1, count); -} - - -function testSendFileUriZeroStatusSuccess() { - MockXmlHttp.syncSend = true; - var count = 0; - - var x = new goog.net.XhrIo; - goog.events.listen(x, goog.net.EventType.COMPLETE, function(e) { - assertFalse('Should not fire complete from inside send', inSend); - assertTrue('Should not be succesful', e.target.isSuccess()); - count++; - }); - - var inSend = true; - x.send(goog.Uri.parse('file:///foo')); - lastMockXmlHttp.status = 0; - inSend = false; - - clock.tick(1); // callOnce(f, 0, ...) - - assertEquals('Complete should have been called once', 1, count); -} - - -function testSendDummyUriZeroStatusSuccess() { - MockXmlHttp.syncSend = true; - var count = 0; - - var x = new goog.net.XhrIo; - goog.events.listen(x, goog.net.EventType.COMPLETE, function(e) { - assertFalse('Should not fire complete from inside send', inSend); - assertTrue('Should not be succesful', e.target.isSuccess()); - count++; - }); - - var inSend = true; - x.send(goog.Uri.parse('dummy:///foo')); - lastMockXmlHttp.status = 0; - inSend = false; - - clock.tick(1); // callOnce(f, 0, ...) - - assertEquals('Complete should have been called once', 1, count); -} - - -function testSendFileUpperUriZeroStatusSuccess() { - MockXmlHttp.syncSend = true; - var count = 0; - - var x = new goog.net.XhrIo; - goog.events.listen(x, goog.net.EventType.COMPLETE, function(e) { - assertFalse('Should not fire complete from inside send', inSend); - assertTrue('Should not be succesful', e.target.isSuccess()); - count++; - }); - - var inSend = true; - x.send(goog.Uri.parse('FILE:///foo')); - lastMockXmlHttp.status = 0; - inSend = false; - - clock.tick(1); // callOnce(f, 0, ...) - - assertEquals('Complete should have been called once', 1, count); -} - - -function testSendFromListener() { - MockXmlHttp.syncSend = true; - var count = 0; - - var x = new goog.net.XhrIo; - goog.events.listen(x, goog.net.EventType.COMPLETE, function(e) { - count++; - - var e = assertThrows(function() { - x.send('url2'); - }); - assertEquals('[goog.net.XhrIo] Object is active with another request', - e.message); - }); - - x.send('url'); - - clock.tick(1); // callOnce(f, 0, ...) - - assertEquals('Complete should have been called once', 1, count); -} - - -function testStatesDuringEvents() { - MockXmlHttp.syncSend = true; - - var x = new goog.net.XhrIo; - var readyState = goog.net.XmlHttp.ReadyState.UNINITIALIZED; - goog.events.listen(x, goog.net.EventType.READY_STATE_CHANGE, function(e) { - readyState++; - assertObjectEquals(e.target, x); - assertEquals(x.getReadyState(), readyState); - assertTrue(x.isActive()); - }); - goog.events.listen(x, goog.net.EventType.COMPLETE, function(e) { - assertObjectEquals(e.target, x); - assertTrue(x.isActive()); - }); - goog.events.listen(x, goog.net.EventType.SUCCESS, function(e) { - assertObjectEquals(e.target, x); - assertTrue(x.isActive()); - }); - goog.events.listen(x, goog.net.EventType.READY, function(e) { - assertObjectEquals(e.target, x); - assertFalse(x.isActive()); - }); - - x.send('url'); - - clock.tick(1); // callOnce(f, 0, ...) -} - - -function testProtectEntryPointCalledOnAsyncSend() { - MockXmlHttp.syncSend = false; - - var errorHandlerCallbackCalled = false; - var errorHandler = new goog.debug.ErrorHandler(function() { - errorHandlerCallbackCalled = true; - }); - - goog.net.XhrIo.protectEntryPoints(errorHandler); - - var x = new goog.net.XhrIo; - goog.events.listen(x, goog.net.EventType.READY_STATE_CHANGE, function(e) { - throw Error(); - }); - - x.send('url'); - assertThrows(function() { - lastMockXmlHttp.complete(); - }); - - assertTrue('Error handler callback should be called on async send.', - errorHandlerCallbackCalled); -} - - -function testDisposeInternalDoesNotAbortXhrRequestObjectWhenActiveIsFalse() { - MockXmlHttp.syncSend = false; - - var xmlHttp = goog.net.XmlHttp; - var abortCalled = false; - var x = new goog.net.XhrIo; - - goog.net.XmlHttp.prototype.abort = function() { abortCalled = true; } - - goog.events.listen(x, goog.net.EventType.COMPLETE, function(e) { - this.active_ = false; - this.dispose(); - }, false, x); - - x.send('url'); - lastMockXmlHttp.complete(); - - goog.net.XmlHttp = xmlHttp; - assertFalse(abortCalled); -} - -function testCallingAbortFromWithinAbortCallbackDoesntLoop() { - var x = new goog.net.XhrIo; - goog.events.listen(x, goog.net.EventType.ABORT, function(e) { - x.abort(); // Shouldn't get a stack overflow - }); - x.send('url'); - x.abort(); -} - -function testFactoryInjection() { - var xhr = new MockXmlHttp(); - var optionsFactoryCalled = 0; - var xhrFactoryCalled = 0; - var wrapperFactory = new goog.net.WrapperXmlHttpFactory( - function() { - xhrFactoryCalled++; - return xhr; - }, - function() { - optionsFactoryCalled++; - return {}; - }); - var xhrIo = new goog.net.XhrIo(wrapperFactory); - - xhrIo.send('url'); - - assertEquals('XHR factory should have been called', 1, xhrFactoryCalled); - assertEquals('Options factory should have been called', 1, - optionsFactoryCalled); -} - -function testGoogTestingNetXhrIoIsInSync() { - var xhrIo = new goog.net.XhrIo(); - var testingXhrIo = new goog.testing.net.XhrIo(); - - var propertyComparator = function(value, key, obj) { - if (goog.string.endsWith(key, '_')) { - // Ignore private properties/methods - return true; - } else if (typeof value == 'function' && typeof this[key] != 'function') { - // Only type check is sufficient for functions - fail('Mismatched property:'+ key + ': gooo.net.XhrIo has:<' + - value + '>; while goog.testing.net.XhrIo has:<' + this[key] + '>'); - return true; - } else { - // Ignore all other type of properties. - return true; - } - }; - - goog.object.every(xhrIo, propertyComparator, testingXhrIo); -} - -function testEntryPointRegistry() { - var monitor = new goog.debug.EntryPointMonitor(); - var replacement = function() {}; - monitor.wrap = goog.testing.recordFunction( - goog.functions.constant(replacement)); - - goog.debug.entryPointRegistry.monitorAll(monitor); - assertTrue(monitor.wrap.getCallCount() >= 1); - assertEquals( - replacement, - goog.net.XhrIo.prototype.onReadyStateChangeEntryPoint_); -} - -function testSetWithCredentials() { - // Test on XHR objects that don't have the withCredentials property (older - // browsers). - var x = new goog.net.XhrIo; - x.setWithCredentials(true); - x.send('url'); - assertFalse( - 'withCredentials should not be set on an XHR object if the property ' + - 'does not exist.', - goog.object.containsKey(lastMockXmlHttp, 'withCredentials')); - - // Test on XHR objects that have the withCredentials property. - MockXmlHttp.prototype.withCredentials = false; - x = new goog.net.XhrIo; - x.setWithCredentials(true); - x.send('url'); - assertTrue( - 'withCredentials should be set on an XHR object if the property exists', - goog.object.containsKey(lastMockXmlHttp, 'withCredentials')); - - assertTrue( - 'withCredentials value not set on XHR object', - lastMockXmlHttp.withCredentials); - - // Reset the prototype so it does not effect other tests. - delete MockXmlHttp.prototype.withCredentials; -} - -function testGetResponse() { - var x = new goog.net.XhrIo; - - // No XHR yet - assertEquals(null, x.getResponse()); - - // XHR with no .response and no response type, gets text. - x.xhr_ = {}; - x.xhr_.responseText = 'text'; - assertEquals('text', x.getResponse()); - - // Response type of text gets text as well. - x.setResponseType(goog.net.XhrIo.ResponseType.TEXT); - x.xhr_.responseText = ''; - assertEquals('', x.getResponse()); - - // Response type of array buffer gets the array buffer. - x.xhr_.mozResponseArrayBuffer = 'ab'; - x.setResponseType(goog.net.XhrIo.ResponseType.ARRAY_BUFFER); - assertEquals('ab', x.getResponse()); - - // With a response field, it is returned no matter what value it has. - x.xhr_.response = undefined; - assertEquals(undefined, x.getResponse()); - - x.xhr_.response = null; - assertEquals(null, x.getResponse()); - - x.xhr_.response = ''; - assertEquals('', x.getResponse()); - - x.xhr_.response = 'resp'; - assertEquals('resp', x.getResponse()); -} - -</script> -</head> - -<body> -</body> - -</html> diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/xhriopool.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/xhriopool.js.svn-base deleted file mode 100644 index 1b2e171..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/xhriopool.js.svn-base +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright 2006 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Creates a pool of XhrIo objects to use. This allows multiple - * XhrIo objects to be grouped together and requests will use next available - * XhrIo object. - * - */ - -goog.provide('goog.net.XhrIoPool'); - -goog.require('goog.net.XhrIo'); -goog.require('goog.structs'); -goog.require('goog.structs.PriorityPool'); - - - -/** - * A pool of XhrIo objects. - * @param {goog.structs.Map=} opt_headers Map of default headers to add to every - * request. - * @param {number=} opt_minCount Minimum number of objects (Default: 1). - * @param {number=} opt_maxCount Maximum number of objects (Default: 10). - * @constructor - * @extends {goog.structs.PriorityPool} - */ -goog.net.XhrIoPool = function(opt_headers, opt_minCount, opt_maxCount) { - goog.structs.PriorityPool.call(this, opt_minCount, opt_maxCount); - - /** - * Map of default headers to add to every request. - * @type {goog.structs.Map|undefined} - * @private - */ - this.headers_ = opt_headers; -}; -goog.inherits(goog.net.XhrIoPool, goog.structs.PriorityPool); - - -/** - * Creates an instance of an XhrIo object to use in the pool. - * @return {goog.net.XhrIo} The created object. - */ -goog.net.XhrIoPool.prototype.createObject = function() { - var xhrIo = new goog.net.XhrIo(); - var headers = this.headers_; - if (headers) { - goog.structs.forEach(headers, function(value, key) { - xhrIo.headers.set(key, value); - }); - } - return xhrIo; -}; - - -/** - * Should be overridden to dispose of an object, default implementation is to - * remove all its members which should render it useless. - * @param {goog.net.XhrIo} obj The object to dispose. - */ -goog.net.XhrIoPool.prototype.disposeObject = function(obj) { - obj.dispose(); -}; - - -/** - * Determine if an object has become unusable and should not be used. - * @param {goog.net.XhrIo} obj The object to test. - * @return {boolean} Whether the object can be reused, which is true if the - * object is not disposed and not active. - */ -goog.net.XhrIoPool.prototype.objectCanBeReused = function(obj) { - // An active XhrIo object should never be used. - return !obj.isDisposed() && !obj.isActive(); -}; diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/xhrlite.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/xhrlite.js.svn-base deleted file mode 100644 index 0e56e4e..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/xhrlite.js.svn-base +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright 2006 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Wrapper class for handling XmlHttpRequests. - */ - - -goog.provide('goog.net.XhrLite'); - -goog.require('goog.net.XhrIo'); - - - -/** - * Basic class for handling XmlHttpRequests. - * @deprecated Use goog.net.XhrIo instead. - * @constructor - */ -goog.net.XhrLite = goog.net.XhrIo; - -// Statics are needed to avoid code removal. - - -/** - * Static send that creates a short lived instance of XhrIo to send the - * request. - * @see goog.net.XhrIo.cleanup - * @param {string} url Uri to make request too. - * @param {Function=} opt_callback Callback function for when request is - * complete. - * @param {string=} opt_method Send method, default: GET. - * @param {string=} opt_content Post data. - * @param {Object|goog.structs.Map=} opt_headers Map of headers to add to the - * request. - * @param {number=} opt_timeoutInterval Number of milliseconds after which an - * incomplete request will be aborted; 0 means no timeout is set. - */ -goog.net.XhrLite.send = goog.net.XhrIo.send; - - -/** - * Disposes all non-disposed instances of goog.net.XhrIo created by - * {@link goog.net.XhrIo.send}. - * {@link goog.net.XhrIo.send} cleans up the goog.net.XhrIo instance - * it creates when the request completes or fails. However, if - * the request never completes, then the goog.net.XhrIo is not disposed. - * This can occur if the window is unloaded before the request completes. - * We could have {@link goog.net.XhrIo.send} return the goog.net.XhrIo - * it creates and make the client of {@link goog.net.XhrIo.send} be - * responsible for disposing it in this case. However, this makes things - * significantly more complicated for the client, and the whole point - * of {@link goog.net.XhrIo.send} is that it's simple and easy to use. - * Clients of {@link goog.net.XhrIo.send} should call - * {@link goog.net.XhrIo.cleanup} when doing final - * cleanup on window unload. - */ -goog.net.XhrLite.cleanup = goog.net.XhrIo.cleanup; - - -/** - * Installs exception protection for all entry point introduced by - * goog.net.XhrIo instances which are not protected by - * {@link goog.debug.ErrorHandler#protectWindowSetTimeout}, - * {@link goog.debug.ErrorHandler#protectWindowSetInterval}, or - * {@link goog.events.protectBrowserEventEntryPoint}. - * - * @param {goog.debug.ErrorHandler} errorHandler Error handler with which to - * protect the entry point(s). - * @param {boolean=} opt_tracers Whether to install tracers around the entry - * point. - */ -goog.net.XhrLite.protectEntryPoints = goog.net.XhrIo.protectEntryPoints; - - -/** - * Disposes of the specified goog.net.XhrIo created by - * {@link goog.net.XhrIo.send} and removes it from - * {@link goog.net.XhrIo.pendingStaticSendInstances_}. - * @param {goog.net.XhrIo} XhrIo An XhrIo created by - * {@link goog.net.XhrIo.send}. - * @private - */ -goog.net.XhrLite.cleanupSend_ = goog.net.XhrIo.cleanupSend_; - - -/** - * The Content-Type HTTP header name - * @type {string} - */ -goog.net.XhrLite.CONTENT_TYPE_HEADER = goog.net.XhrIo.CONTENT_TYPE_HEADER; - - -/** - * The Content-Type HTTP header value for a url-encoded form - * @type {string} - */ -goog.net.XhrLite.FORM_CONTENT_TYPE = goog.net.XhrIo.FORM_CONTENT_TYPE; - - -/** - * All non-disposed instances of goog.net.XhrIo created - * by {@link goog.net.XhrIo.send} are in this Array. - * @see goog.net.XhrIo.cleanup - * @type {Array.<goog.net.XhrIo>} - * @private - */ -goog.net.XhrLite.sendInstances_ = goog.net.XhrIo.sendInstances_; diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/xhrlite_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/xhrlite_test.html.svn-base deleted file mode 100644 index 9f91788..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/xhrlite_test.html.svn-base +++ /dev/null @@ -1,157 +0,0 @@ -<!DOCTYPE html> -<html> -<!-- -Copyright 2007 The Closure Library Authors. All Rights Reserved. - -Use of this source code is governed by the Apache License, Version 2.0. -See the COPYING file for details. ---> -<!-- - Author: arv@google.com (Erik Arvidsson) ---> -<head> -<meta http-equiv="X-UA-Compatible" content="IE=edge"> -<title>Closure Unit Tests - goog.net.XhrLite</title> -<script src="../base.js"></script> -<script> - goog.require('goog.debug.ErrorHandler'); - goog.require('goog.net.WrapperXmlHttpFactory'); - goog.require('goog.net.XhrLite'); - goog.require('goog.testing.MockClock'); - goog.require('goog.testing.jsunit'); -</script> -<script> - -function MockXmlHttp() {} - -MockXmlHttp.prototype.readyState = goog.net.XmlHttp.ReadyState.UNINITIALIZED; - -MockXmlHttp.prototype.status = 200; - -MockXmlHttp.syncSend = false; - -MockXmlHttp.prototype.send = function(opt_data) { - this.readyState = goog.net.XmlHttp.ReadyState.UNINITIALIZED; - - if (MockXmlHttp.syncSend) { - this.complete(); - } - -}; - -MockXmlHttp.prototype.complete = function() { - this.readyState = goog.net.XmlHttp.ReadyState.LOADING; - this.onreadystatechange(); - - this.readyState = goog.net.XmlHttp.ReadyState.LOADED; - this.onreadystatechange(); - - this.readyState = goog.net.XmlHttp.ReadyState.INTERACTIVE; - this.onreadystatechange(); - - this.readyState = goog.net.XmlHttp.ReadyState.COMPLETE; - this.onreadystatechange(); -}; - - -MockXmlHttp.prototype.open = function(verb, uri, async) { -}; - -MockXmlHttp.prototype.abort = function() {}; - -MockXmlHttp.prototype.setRequestHeader = function(key, value) {}; - -goog.net.XmlHttp.setGlobalFactory(new goog.net.WrapperXmlHttpFactory( - function() { - return new MockXmlHttp(); - }, - function() { - return {}; - })); - -var clock; - -function setUp() { - clock = new goog.testing.MockClock(true); -} - -function tearDown() { - clock.dispose(); -} - - -function testSyncSend() { - MockXmlHttp.syncSend = true; - var count = 0; - - var x = new goog.net.XhrLite; - goog.events.listen(x, goog.net.EventType.COMPLETE, function(e) { - assertFalse('Should not fire complete from inside send', inSend); - assertTrue('Should be succesful', e.target.isSuccess()); - count++; - - }); - - var inSend = true; - x.send('url'); - inSend = false; - - clock.tick(1); // callOnce(f, 0, ...) - - assertEquals('Complete should have been called once', 1, count); -} - -function testSyncSendFailure() { - MockXmlHttp.syncSend = true; - var count = 0; - - var x = new goog.net.XhrLite; - goog.events.listen(x, goog.net.EventType.COMPLETE, function(e) { - assertFalse('Should not fire complete from inside send', inSend); - assertFalse('Should not be succesful', e.target.isSuccess()); - count++; - }); - - var inSend = true; - x.send('url'); - x.xhr_.status = 404; - inSend = false; - - clock.tick(1); // callOnce(f, 0, ...) - - assertEquals('Complete should have been called once', 1, count); -} - - -function testProtectEntryPointCalledOnAsyncSend() { - MockXmlHttp.syncSend = false; - - var errorHandlerCallbackCalled = false; - var errorHandler = new goog.debug.ErrorHandler(function() { - errorHandlerCallbackCalled = true; - }); - - goog.net.XhrLite.protectEntryPoints(errorHandler); - - var x = new goog.net.XhrLite; - goog.events.listen(x, goog.net.EventType.READY_STATE_CHANGE, function(e) { - throw Error(); - }); - - x.send('url'); - assertThrows(function() { - x.xhr_.complete(); - }); - - assertTrue('Error handler callback should be called on async send.', - errorHandlerCallbackCalled); -} - - -</script> -</head> - -<body> -</body> - -</html> diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/xhrlitepool.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/xhrlitepool.js.svn-base deleted file mode 100644 index 9e4ce85..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/xhrlitepool.js.svn-base +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2006 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Creates a pool of XhrLite objects to use. This allows multiple - * XhrLite objects to be grouped together and requests will use next available - * XhrLite object. - * - */ - -goog.provide('goog.net.XhrLitePool'); - -goog.require('goog.net.XhrIoPool'); - - - -/** - * A pool of XhrLite objects. - * @param {goog.structs.Map=} opt_headers Map of default headers to add to every - * request. - * @param {number=} opt_minCount Min. number of objects (Default: 1). - * @param {number=} opt_maxCount Max. number of objects (Default: 10). - * @deprecated Use goog.net.XhrIoPool. - * @constructor - */ -goog.net.XhrLitePool = goog.net.XhrIoPool; diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/xhrmanager.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/xhrmanager.js.svn-base deleted file mode 100644 index 36339f4..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/xhrmanager.js.svn-base +++ /dev/null @@ -1,757 +0,0 @@ -// Copyright 2006 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Manages a pool of XhrIo's. This handles all the details of - * dealing with the XhrPool and provides a simple interface for sending requests - * and managing events. - * - * This class supports queueing & prioritization of requests (XhrIoPool - * handles this) and retrying of requests. - * - * The events fired by the XhrManager are an aggregation of the events of - * each of its XhrIo objects (with some filtering, i.e., ERROR only called - * when there are no more retries left). For this reason, all send requests have - * to have an id, so that the user of this object can know which event is for - * which request. - * - */ - -goog.provide('goog.net.XhrManager'); -goog.provide('goog.net.XhrManager.Event'); -goog.provide('goog.net.XhrManager.Request'); - -goog.require('goog.Disposable'); -goog.require('goog.events'); -goog.require('goog.events.Event'); -goog.require('goog.events.EventHandler'); -goog.require('goog.events.EventTarget'); -goog.require('goog.net.EventType'); -goog.require('goog.net.XhrIo'); -goog.require('goog.net.XhrIoPool'); -goog.require('goog.structs.Map'); - -// TODO(user): Add some time in between retries. - - - -/** - * A manager of an XhrIoPool. - * @param {number=} opt_maxRetries Max. number of retries (Default: 1). - * @param {goog.structs.Map=} opt_headers Map of default headers to add to every - * request. - * @param {number=} opt_minCount Min. number of objects (Default: 1). - * @param {number=} opt_maxCount Max. number of objects (Default: 10). - * @param {number=} opt_timeoutInterval Timeout (in ms) before aborting an - * attempt (Default: 0ms). - * @constructor - * @extends {goog.events.EventTarget} - */ -goog.net.XhrManager = function( - opt_maxRetries, - opt_headers, - opt_minCount, - opt_maxCount, - opt_timeoutInterval) { - - /** - * Maximum number of retries for a given request - * @type {number} - * @private - */ - this.maxRetries_ = goog.isDef(opt_maxRetries) ? opt_maxRetries : 1; - - /** - * Timeout interval for an attempt of a given request. - * @type {number} - * @private - */ - this.timeoutInterval_ = - goog.isDef(opt_timeoutInterval) ? Math.max(0, opt_timeoutInterval) : 0; - - /** - * The pool of XhrIo's to use. - * @type {goog.net.XhrIoPool} - * @private - */ - this.xhrPool_ = new goog.net.XhrIoPool( - opt_headers, opt_minCount, opt_maxCount); - - /** - * Map of ID's to requests. - * @type {goog.structs.Map} - * @private - */ - this.requests_ = new goog.structs.Map(); - - /** - * The event handler. - * @type {goog.events.EventHandler} - * @private - */ - this.eventHandler_ = new goog.events.EventHandler(this); -}; -goog.inherits(goog.net.XhrManager, goog.events.EventTarget); - - -/** - * Error to throw when a send is attempted with an ID that the manager already - * has registered for another request. - * @type {string} - * @private - */ -goog.net.XhrManager.ERROR_ID_IN_USE_ = '[goog.net.XhrManager] ID in use'; - - -/** - * The goog.net.EventType's to listen/unlisten for on the XhrIo object. - * @type {Array.<goog.net.EventType>} - * @private - */ -goog.net.XhrManager.XHR_EVENT_TYPES_ = [ - goog.net.EventType.READY, - goog.net.EventType.COMPLETE, - goog.net.EventType.SUCCESS, - goog.net.EventType.ERROR, - goog.net.EventType.ABORT, - goog.net.EventType.TIMEOUT]; - - -/** - * Sets the number of milliseconds after which an incomplete request will be - * aborted. Zero means no timeout is set. - * @param {number} ms Timeout interval in milliseconds; 0 means none. - */ -goog.net.XhrManager.prototype.setTimeoutInterval = function(ms) { - this.timeoutInterval_ = Math.max(0, ms); -}; - - -/** - * Returns the number of reuqests either in flight, or waiting to be sent. - * @return {number} The number of requests in flight or pending send. - */ -goog.net.XhrManager.prototype.getOutstandingCount = function() { - return this.requests_.getCount(); -}; - - -/** - * Registers the given request to be sent. Throws an error if a request - * already exists with the given ID. - * NOTE: It is not sent immediately. It is queued and will be sent when an - * XhrIo object becomes available, taking into account the request's - * priority. - * @param {string} id The id of the request. - * @param {string} url Uri to make the request too. - * @param {string=} opt_method Send method, default: GET. - * @param {string=} opt_content Post data. - * @param {Object|goog.structs.Map=} opt_headers Map of headers to add to the - * request. - * @param {*=} opt_priority The priority of the request. - * @param {Function=} opt_callback Callback function for when request is - * complete. The only param is the event object from the COMPLETE event. - * @param {number=} opt_maxRetries The maximum number of times the request - * should be retried. - * @return {goog.net.XhrManager.Request} The queued request object. - */ -goog.net.XhrManager.prototype.send = function( - id, - url, - opt_method, - opt_content, - opt_headers, - opt_priority, - opt_callback, - opt_maxRetries) { - var requests = this.requests_; - // Check if there is already a request with the given id. - if (requests.get(id)) { - throw Error(goog.net.XhrManager.ERROR_ID_IN_USE_); - } - - // Make the Request object. - var request = new goog.net.XhrManager.Request( - url, - goog.bind(this.handleEvent_, this, id), - opt_method, - opt_content, - opt_headers, - opt_callback, - goog.isDef(opt_maxRetries) ? opt_maxRetries : this.maxRetries_); - this.requests_.set(id, request); - - // Setup the callback for the pool. - var callback = goog.bind(this.handleAvailableXhr_, this, id); - this.xhrPool_.getObject(callback, opt_priority); - - return request; -}; - - -/** - * Aborts the request associated with id. - * @param {string} id The id of the request to abort. - * @param {boolean=} opt_force If true, remove the id now so it can be reused. - * No events are fired and the callback is not called when forced. - */ -goog.net.XhrManager.prototype.abort = function(id, opt_force) { - var request = this.requests_.get(id); - if (request) { - var xhrIo = request.xhrIo; - request.setAborted(true); - if (opt_force) { - // We remove listeners to make sure nothing gets called if a new request - // with the same id is made. - this.removeXhrListener_(xhrIo, request.getXhrEventCallback()); - goog.events.listenOnce( - xhrIo, - goog.net.EventType.READY, - function() { this.xhrPool_.releaseObject(xhrIo); }, - false, - this); - this.requests_.remove(id); - } - if (xhrIo) { - xhrIo.abort(); - } - } -}; - - -/** - * Handles when an XhrIo object becomes available. Sets up the events, fires - * the READY event, and starts the process to send the request. - * @param {string} id The id of the request the XhrIo is for. - * @param {goog.net.XhrIo} xhrIo The available XhrIo object. - * @private - */ -goog.net.XhrManager.prototype.handleAvailableXhr_ = function(id, xhrIo) { - var request = this.requests_.get(id); - // Make sure the request doesn't already have an XhrIo attached. This can - // happen if a forced abort occurs before an XhrIo is available, and a new - // request with the same id is made. - if (request && !request.xhrIo) { - this.addXhrListener_(xhrIo, request.getXhrEventCallback()); - - // Set properties for the XhrIo. - xhrIo.setTimeoutInterval(this.timeoutInterval_); - - // Add a reference to the XhrIo object to the request. - request.xhrIo = request.xhrLite = xhrIo; - - // Notify the listeners. - this.dispatchEvent(new goog.net.XhrManager.Event( - goog.net.EventType.READY, this, id, xhrIo)); - - // Send the request. - this.retry_(id, xhrIo); - - // If the request was aborted before it got an XhrIo object, abort it now. - if (request.getAborted()) { - xhrIo.abort(); - } - } else { - // If the request has an XhrIo object already, or no request exists, just - // return the XhrIo back to the pool. - this.xhrPool_.releaseObject(xhrIo); - } -}; - - -/** - * Handles all events fired by the XhrIo object for a given request. - * @param {string} id The id of the request. - * @param {goog.events.Event} e The event. - * @return {Object} The return value from the handler, if any. - * @private - */ -goog.net.XhrManager.prototype.handleEvent_ = function(id, e) { - var xhrIo = /** @type {goog.net.XhrIo} */(e.target); - switch (e.type) { - case goog.net.EventType.READY: - this.retry_(id, xhrIo); - break; - - case goog.net.EventType.COMPLETE: - return this.handleComplete_(id, xhrIo, e); - - case goog.net.EventType.SUCCESS: - this.handleSuccess_(id, xhrIo); - break; - - // A timeout is handled like an error. - case goog.net.EventType.TIMEOUT: - case goog.net.EventType.ERROR: - this.handleError_(id, xhrIo); - break; - - case goog.net.EventType.ABORT: - this.handleAbort_(id, xhrIo); - break; - } - return null; -}; - - -/** - * Attempts to retry the given request. If the request has already attempted - * the maximum number of retries, then it removes the request and releases - * the XhrIo object back into the pool. - * @param {string} id The id of the request. - * @param {goog.net.XhrIo} xhrIo The XhrIo object. - * @private - */ -goog.net.XhrManager.prototype.retry_ = function(id, xhrIo) { - var request = this.requests_.get(id); - - // If the request has not completed and it is below its max. retries. - if (request && !request.getCompleted() && !request.hasReachedMaxRetries()) { - request.increaseAttemptCount(); - xhrIo.send(request.getUrl(), request.getMethod(), request.getContent(), - request.getHeaders()); - } else { - if (request) { - // Remove the events on the XhrIo objects. - this.removeXhrListener_(xhrIo, request.getXhrEventCallback()); - - // Remove the request. - this.requests_.remove(id); - } - // Release the XhrIo object back into the pool. - this.xhrPool_.releaseObject(xhrIo); - } -}; - - -/** - * Handles the complete of a request. Dispatches the COMPLETE event and sets the - * the request as completed if the request has succeeded, or is done retrying. - * @param {string} id The id of the request. - * @param {goog.net.XhrIo} xhrIo The XhrIo object. - * @param {goog.events.Event} e The original event. - * @return {Object} The return value from the callback, if any. - * @private - */ -goog.net.XhrManager.prototype.handleComplete_ = function(id, xhrIo, e) { - // Only if the request is done processing should a COMPLETE event be fired. - var request = this.requests_.get(id); - if (xhrIo.getLastErrorCode() == goog.net.ErrorCode.ABORT || - xhrIo.isSuccess() || request.hasReachedMaxRetries()) { - this.dispatchEvent(new goog.net.XhrManager.Event( - goog.net.EventType.COMPLETE, this, id, xhrIo)); - - // If the request exists, we mark it as completed and call the callback - if (request) { - request.setCompleted(true); - // Call the complete callback as if it was set as a COMPLETE event on the - // XhrIo directly. - if (request.getCompleteCallback()) { - return request.getCompleteCallback().call(xhrIo, e); - } - } - } - return null; -}; - - -/** - * Handles the abort of an underlying XhrIo object. - * @param {string} id The id of the request. - * @param {goog.net.XhrIo} xhrIo The XhrIo object. - * @private - */ -goog.net.XhrManager.prototype.handleAbort_ = function(id, xhrIo) { - // Fire event. - // NOTE: The complete event should always be fired before the abort event, so - // the bulk of the work is done in handleComplete. - this.dispatchEvent(new goog.net.XhrManager.Event( - goog.net.EventType.ABORT, this, id, xhrIo)); -}; - - -/** - * Handles the success of a request. Dispatches the SUCCESS event and sets the - * the request as completed. - * @param {string} id The id of the request. - * @param {goog.net.XhrIo} xhrIo The XhrIo object. - * @private - */ -goog.net.XhrManager.prototype.handleSuccess_ = function(id, xhrIo) { - // Fire event. - // NOTE: We don't release the XhrIo object from the pool here. - // It is released in the retry method, when we know it is back in the - // ready state. - this.dispatchEvent(new goog.net.XhrManager.Event( - goog.net.EventType.SUCCESS, this, id, xhrIo)); -}; - - -/** - * Handles the error of a request. If the request has not reach its maximum - * number of retries, then it lets the request retry naturally (will let the - * request hit the READY state). Else, it dispatches the ERROR event. - * @param {string} id The id of the request. - * @param {goog.net.XhrIo} xhrIo The XhrIo object. - * @private - */ -goog.net.XhrManager.prototype.handleError_ = function(id, xhrIo) { - var request = this.requests_.get(id); - - // If the maximum number of retries has been reached. - if (request.hasReachedMaxRetries()) { - // Fire event. - // NOTE: We don't release the XhrIo object from the pool here. - // It is released in the retry method, when we know it is back in the - // ready state. - this.dispatchEvent(new goog.net.XhrManager.Event( - goog.net.EventType.ERROR, this, id, xhrIo)); - } -}; - - -/** - * Remove listeners for XHR events on an XhrIo object. - * @param {goog.net.XhrIo} xhrIo The object to stop listenening to events on. - * @param {Function} func The callback to remove from event handling. - * @param {string|Array.<string>=} opt_types Event types to remove listeners - * for. Defaults to XHR_EVENT_TYPES_. - * @private - */ -goog.net.XhrManager.prototype.removeXhrListener_ = function(xhrIo, - func, - opt_types) { - var types = opt_types || goog.net.XhrManager.XHR_EVENT_TYPES_; - this.eventHandler_.unlisten(xhrIo, types, func); -}; - - -/** - * Adds a listener for XHR events on an XhrIo object. - * @param {goog.net.XhrIo} xhrIo The object listen to events on. - * @param {Function} func The callback when the event occurs. - * @param {string|Array.<string>=} opt_types Event types to attach listeners to. - * Defaults to XHR_EVENT_TYPES_. - * @private - */ -goog.net.XhrManager.prototype.addXhrListener_ = function(xhrIo, - func, - opt_types) { - var types = opt_types || goog.net.XhrManager.XHR_EVENT_TYPES_; - this.eventHandler_.listen(xhrIo, types, func); -}; - - -/** @override */ -goog.net.XhrManager.prototype.disposeInternal = function() { - goog.net.XhrManager.superClass_.disposeInternal.call(this); - - this.xhrPool_.dispose(); - this.xhrPool_ = null; - - this.eventHandler_.dispose(); - this.eventHandler_ = null; - - // Call dispose on each request. - var requests = this.requests_; - goog.structs.forEach(requests, function(value, key) { - value.dispose(); - }); - requests.clear(); - this.requests_ = null; -}; - - - -/** - * An event dispatched by XhrManager. - * - * @param {goog.net.EventType} type Event Type. - * @param {goog.net.XhrManager} target Reference to the object that is the - * target of this event. - * @param {string} id The id of the request this event is for. - * @param {goog.net.XhrIo} xhrIo The XhrIo object of the request. - * @constructor - * @extends {goog.events.Event} - */ -goog.net.XhrManager.Event = function(type, target, id, xhrIo) { - goog.events.Event.call(this, type, target); - - /** - * The id of the request this event is for. - * @type {string} - */ - this.id = id; - - /** - * The XhrIo object of the request. - * @type {goog.net.XhrIo} - */ - this.xhrIo = xhrIo; - - /** - * The xhrLite field aliases xhrIo for backwards compatibility. - * @type {goog.net.XhrLite} - */ - this.xhrLite = /** @type {goog.net.XhrLite} */ (xhrIo); -}; -goog.inherits(goog.net.XhrManager.Event, goog.events.Event); - - -/** @override */ -goog.net.XhrManager.Event.prototype.disposeInternal = function() { - goog.net.XhrManager.Event.superClass_.disposeInternal.call(this); - delete this.id; - this.xhrIo = null; - this.xhrLite = null; -}; - - - -/** - * An encapsulation of everything needed to make a Xhr request. - * NOTE: This is used internal to the XhrManager. - * - * @param {string} url Uri to make the request too. - * @param {Function} xhrEventCallback Callback attached to the events of the - * XhrIo object of the request. - * @param {string=} opt_method Send method, default: GET. - * @param {string=} opt_content Post data. - * @param {Object|goog.structs.Map=} opt_headers Map of headers to add to the - * request. - * @param {Function=} opt_callback Callback function for when request is - * complete. NOTE: Only 1 callback supported across all events. - * @param {number=} opt_maxRetries The maximum number of times the request - * should be retried (Default: 1). - * - * @constructor - * @extends {goog.Disposable} - */ -goog.net.XhrManager.Request = function(url, xhrEventCallback, opt_method, - opt_content, opt_headers, opt_callback, opt_maxRetries) { - goog.Disposable.call(this); - - /** - * Uri to make the request too. - * @type {string} - * @private - */ - this.url_ = url; - - /** - * Send method. - * @type {string} - * @private - */ - this.method_ = opt_method || 'GET'; - - /** - * Post data. - * @type {string|undefined} - * @private - */ - this.content_ = opt_content; - - /** - * Map of headers - * @type {Object|goog.structs.Map|null} - * @private - */ - this.headers_ = opt_headers || null; - - /** - * The maximum number of times the request should be retried. - * @type {number} - * @private - */ - this.maxRetries_ = goog.isDef(opt_maxRetries) ? opt_maxRetries : 1; - - /** - * The number of attempts so far. - * @type {number} - * @private - */ - this.attemptCount_ = 0; - - /** - * Whether the request has been completed. - * @type {boolean} - * @private - */ - this.completed_ = false; - - /** - * Whether the request has been aborted. - * @type {boolean} - * @private - */ - this.aborted_ = false; - - /** - * Callback attached to the events of the XhrIo object. - * @type {Function|undefined} - * @private - */ - this.xhrEventCallback_ = xhrEventCallback; - - /** - * Callback function called when request is complete. - * @type {Function|undefined} - * @private - */ - this.completeCallback_ = opt_callback; - - /** - * The XhrIo instance handling this request. Set in handleAvailableXhr. - * @type {goog.net.XhrIo} - */ - this.xhrIo = null; - -}; -goog.inherits(goog.net.XhrManager.Request, goog.Disposable); - - -/** - * Gets the uri. - * @return {string} The uri to make the request to. - */ -goog.net.XhrManager.Request.prototype.getUrl = function() { - return this.url_; -}; - - -/** - * Gets the send method. - * @return {string} The send method. - */ -goog.net.XhrManager.Request.prototype.getMethod = function() { - return this.method_; -}; - - -/** - * Gets the post data. - * @return {string|undefined} The post data. - */ -goog.net.XhrManager.Request.prototype.getContent = function() { - return this.content_; -}; - - -/** - * Gets the map of headers. - * @return {Object|goog.structs.Map} The map of headers. - */ -goog.net.XhrManager.Request.prototype.getHeaders = function() { - return this.headers_; -}; - - -/** - * Gets the maximum number of times the request should be retried. - * @return {number} The maximum number of times the request should be retried. - */ -goog.net.XhrManager.Request.prototype.getMaxRetries = function() { - return this.maxRetries_; -}; - - -/** - * Gets the number of attempts so far. - * @return {number} The number of attempts so far. - */ -goog.net.XhrManager.Request.prototype.getAttemptCount = function() { - return this.attemptCount_; -}; - - -/** - * Increases the number of attempts so far. - */ -goog.net.XhrManager.Request.prototype.increaseAttemptCount = function() { - this.attemptCount_++; -}; - - -/** - * Returns whether the request has reached the maximum number of retries. - * @return {boolean} Whether the request has reached the maximum number of - * retries. - */ -goog.net.XhrManager.Request.prototype.hasReachedMaxRetries = function() { - return this.attemptCount_ > this.maxRetries_; -}; - - -/** - * Sets the completed status. - * @param {boolean} complete The completed status. - */ -goog.net.XhrManager.Request.prototype.setCompleted = function(complete) { - this.completed_ = complete; -}; - - -/** - * Gets the completed status. - * @return {boolean} The completed status. - */ -goog.net.XhrManager.Request.prototype.getCompleted = function() { - return this.completed_; -}; - - -/** - * Sets the aborted status. - * @param {boolean} aborted True if the request was aborted, otherwise False. - */ -goog.net.XhrManager.Request.prototype.setAborted = function(aborted) { - this.aborted_ = aborted; -}; - - -/** - * Gets the aborted status. - * @return {boolean} True if request was aborted, otherwise False. - */ -goog.net.XhrManager.Request.prototype.getAborted = function() { - return this.aborted_; -}; - - -/** - * Gets the callback attached to the events of the XhrIo object. - * @return {Function|undefined} The callback attached to the events of the - * XhrIo object. - */ -goog.net.XhrManager.Request.prototype.getXhrEventCallback = function() { - return this.xhrEventCallback_; -}; - - -/** - * Gets the callback for when the request is complete. - * @return {Function|undefined} The callback for when the request is complete. - */ -goog.net.XhrManager.Request.prototype.getCompleteCallback = function() { - return this.completeCallback_; -}; - - -/** @override */ -goog.net.XhrManager.Request.prototype.disposeInternal = function() { - goog.net.XhrManager.Request.superClass_.disposeInternal.call(this); - delete this.xhrEventCallback_; - delete this.completeCallback_; -}; diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/xmlhttp.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/xmlhttp.js.svn-base deleted file mode 100644 index da85a65..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/xmlhttp.js.svn-base +++ /dev/null @@ -1,217 +0,0 @@ -// Copyright 2006 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Low level handling of XMLHttpRequest. - * @author arv@google.com (Erik Arvidsson) - * @author dbk@google.com (David Barrett-Kahn) - */ - -goog.provide('goog.net.DefaultXmlHttpFactory'); -goog.provide('goog.net.XmlHttp'); -goog.provide('goog.net.XmlHttp.OptionType'); -goog.provide('goog.net.XmlHttp.ReadyState'); - -goog.require('goog.net.WrapperXmlHttpFactory'); -goog.require('goog.net.XmlHttpFactory'); - - -/** - * Static class for creating XMLHttpRequest objects. - * @return {!(XMLHttpRequest|GearsHttpRequest)} A new XMLHttpRequest object. - */ -goog.net.XmlHttp = function() { - return goog.net.XmlHttp.factory_.createInstance(); -}; - - -/** - * Gets the options to use with the XMLHttpRequest objects obtained using - * the static methods. - * @return {Object} The options. - */ -goog.net.XmlHttp.getOptions = function() { - return goog.net.XmlHttp.factory_.getOptions(); -}; - - -/** - * Type of options that an XmlHttp object can have. - * @enum {number} - */ -goog.net.XmlHttp.OptionType = { - /** - * Whether a goog.nullFunction should be used to clear the onreadystatechange - * handler instead of null. - */ - USE_NULL_FUNCTION: 0, - - /** - * NOTE(user): In IE if send() errors on a *local* request the readystate - * is still changed to COMPLETE. We need to ignore it and allow the - * try/catch around send() to pick up the error. - */ - LOCAL_REQUEST_ERROR: 1 -}; - - -/** - * Status constants for XMLHTTP, matches: - * http://msdn.microsoft.com/library/default.asp?url=/library/ - * en-us/xmlsdk/html/0e6a34e4-f90c-489d-acff-cb44242fafc6.asp - * @enum {number} - */ -goog.net.XmlHttp.ReadyState = { - /** - * Constant for when xmlhttprequest.readyState is uninitialized - */ - UNINITIALIZED: 0, - - /** - * Constant for when xmlhttprequest.readyState is loading. - */ - LOADING: 1, - - /** - * Constant for when xmlhttprequest.readyState is loaded. - */ - LOADED: 2, - - /** - * Constant for when xmlhttprequest.readyState is in an interactive state. - */ - INTERACTIVE: 3, - - /** - * Constant for when xmlhttprequest.readyState is completed - */ - COMPLETE: 4 -}; - - -/** - * The global factory instance for creating XMLHttpRequest objects. - * @type {goog.net.XmlHttpFactory} - * @private - */ -goog.net.XmlHttp.factory_; - - -/** - * Sets the factories for creating XMLHttpRequest objects and their options. - * @param {Function} factory The factory for XMLHttpRequest objects. - * @param {Function} optionsFactory The factory for options. - * @deprecated Use setGlobalFactory instead. - */ -goog.net.XmlHttp.setFactory = function(factory, optionsFactory) { - goog.net.XmlHttp.setGlobalFactory(new goog.net.WrapperXmlHttpFactory( - (/** @type {function() : !(XMLHttpRequest|GearsHttpRequest)} */ factory), - (/** @type {function() : !Object}*/ optionsFactory))); -}; - - -/** - * Sets the global factory object. - * @param {!goog.net.XmlHttpFactory} factory New global factory object. - */ -goog.net.XmlHttp.setGlobalFactory = function(factory) { - goog.net.XmlHttp.factory_ = factory; -}; - - - -/** - * Default factory to use when creating xhr objects. You probably shouldn't be - * instantiating this directly, but rather using it via goog.net.XmlHttp. - * @extends {goog.net.XmlHttpFactory} - * @constructor - */ -goog.net.DefaultXmlHttpFactory = function() { - goog.net.XmlHttpFactory.call(this); -}; -goog.inherits(goog.net.DefaultXmlHttpFactory, goog.net.XmlHttpFactory); - - -/** @override */ -goog.net.DefaultXmlHttpFactory.prototype.createInstance = function() { - var progId = this.getProgId_(); - if (progId) { - return new ActiveXObject(progId); - } else { - return new XMLHttpRequest(); - } -}; - - -/** @override */ -goog.net.DefaultXmlHttpFactory.prototype.internalGetOptions = function() { - var progId = this.getProgId_(); - var options = {}; - if (progId) { - options[goog.net.XmlHttp.OptionType.USE_NULL_FUNCTION] = true; - options[goog.net.XmlHttp.OptionType.LOCAL_REQUEST_ERROR] = true; - } - return options; -}; - - -/** - * The ActiveX PROG ID string to use to create xhr's in IE. Lazily initialized. - * @type {?string} - * @private - */ -goog.net.DefaultXmlHttpFactory.prototype.ieProgId_ = null; - - -/** - * Initialize the private state used by other functions. - * @return {string} The ActiveX PROG ID string to use to create xhr's in IE. - * @private - */ -goog.net.DefaultXmlHttpFactory.prototype.getProgId_ = function() { - // The following blog post describes what PROG IDs to use to create the - // XMLHTTP object in Internet Explorer: - // http://blogs.msdn.com/xmlteam/archive/2006/10/23/using-the-right-version-of-msxml-in-internet-explorer.aspx - // However we do not (yet) fully trust that this will be OK for old versions - // of IE on Win9x so we therefore keep the last 2. - if (!this.ieProgId_ && typeof XMLHttpRequest == 'undefined' && - typeof ActiveXObject != 'undefined') { - // Candidate Active X types. - var ACTIVE_X_IDENTS = ['MSXML2.XMLHTTP.6.0', 'MSXML2.XMLHTTP.3.0', - 'MSXML2.XMLHTTP', 'Microsoft.XMLHTTP']; - for (var i = 0; i < ACTIVE_X_IDENTS.length; i++) { - var candidate = ACTIVE_X_IDENTS[i]; - /** @preserveTry */ - try { - new ActiveXObject(candidate); - // NOTE(user): cannot assign progid and return candidate in one line - // because JSCompiler complaings: BUG 658126 - this.ieProgId_ = candidate; - return candidate; - } catch (e) { - // do nothing; try next choice - } - } - - // couldn't find any matches - throw Error('Could not create ActiveXObject. ActiveX might be disabled,' + - ' or MSXML might not be installed'); - } - - return /** @type {string} */ (this.ieProgId_); -}; - - -//Set the global factory to an instance of the default factory. -goog.net.XmlHttp.setGlobalFactory(new goog.net.DefaultXmlHttpFactory()); diff --git a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/xmlhttpfactory.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/xmlhttpfactory.js.svn-base deleted file mode 100644 index ef2c719..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/.svn/text-base/xmlhttpfactory.js.svn-base +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright 2010 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Interface for a factory for creating XMLHttpRequest objects - * and metadata about them. - * @author dbk@google.com (David Barrett-Kahn) - */ - -goog.provide('goog.net.XmlHttpFactory'); - - - -/** - * Abstract base class for an XmlHttpRequest factory. - * @constructor - */ -goog.net.XmlHttpFactory = function() { -}; - - -/** - * Cache of options - we only actually call internalGetOptions once. - * @type {Object} - * @private - */ -goog.net.XmlHttpFactory.prototype.cachedOptions_ = null; - - -/** - * @return {!(XMLHttpRequest|GearsHttpRequest)} A new XMLHttpRequest instance. - */ -goog.net.XmlHttpFactory.prototype.createInstance = goog.abstractMethod; - - -/** - * @return {Object} Options describing how xhr objects obtained from this - * factory should be used. - */ -goog.net.XmlHttpFactory.prototype.getOptions = function() { - return this.cachedOptions_ || - (this.cachedOptions_ = this.internalGetOptions()); -}; - - -/** - * Override this method in subclasses to preserve the caching offered by - * getOptions(). - * @return {Object} Options describing how xhr objects obtained from this - * factory should be used. - * @protected - */ -goog.net.XmlHttpFactory.prototype.internalGetOptions = goog.abstractMethod; diff --git a/contexts/data/lib/closure-library/closure/goog/net/browserchannel.js b/contexts/data/lib/closure-library/closure/goog/net/browserchannel.js index fbfef88..7390500 100644 --- a/contexts/data/lib/closure-library/closure/goog/net/browserchannel.js +++ b/contexts/data/lib/closure-library/closure/goog/net/browserchannel.js @@ -39,6 +39,8 @@ goog.provide('goog.net.BrowserChannel.Event'); goog.provide('goog.net.BrowserChannel.Handler'); goog.provide('goog.net.BrowserChannel.LogSaver'); goog.provide('goog.net.BrowserChannel.QueuedMap'); +goog.provide('goog.net.BrowserChannel.ServerReachability'); +goog.provide('goog.net.BrowserChannel.ServerReachabilityEvent'); goog.provide('goog.net.BrowserChannel.Stat'); goog.provide('goog.net.BrowserChannel.StatEvent'); goog.provide('goog.net.BrowserChannel.State'); @@ -46,11 +48,13 @@ goog.provide('goog.net.BrowserChannel.TimingEvent'); goog.require('goog.Uri'); goog.require('goog.array'); +goog.require('goog.asserts'); goog.require('goog.debug.Logger'); goog.require('goog.debug.TextFormatter'); goog.require('goog.events.Event'); goog.require('goog.events.EventTarget'); goog.require('goog.json'); +goog.require('goog.json.EvalJsonProcessor'); goog.require('goog.net.BrowserTestChannel'); goog.require('goog.net.ChannelDebug'); goog.require('goog.net.ChannelRequest'); @@ -67,22 +71,22 @@ goog.require('goog.userAgent'); /** * Encapsulates the logic for a single BrowserChannel. * - * @param {string} clientVersion An application-specific version number that - * is sent to the server when connected. + * @param {string=} opt_clientVersion An application-specific version number + * that is sent to the server when connected. * @constructor */ -goog.net.BrowserChannel = function(clientVersion) { +goog.net.BrowserChannel = function(opt_clientVersion) { /** * The application specific version that is passed to the server. - * @type {string} + * @type {?string} * @private */ - this.clientVersion_ = clientVersion; + this.clientVersion_ = opt_clientVersion || null; /** * The current state of the BrowserChannel. It should be one of the * goog.net.BrowserChannel.State constants. - * @type {goog.net.BrowserChannel.State} + * @type {!goog.net.BrowserChannel.State} * @private */ this.state_ = goog.net.BrowserChannel.State.INIT; @@ -105,10 +109,18 @@ goog.net.BrowserChannel = function(clientVersion) { /** * The channel debug used for browserchannel logging - * @type {goog.net.ChannelDebug} + * @type {!goog.net.ChannelDebug} * @private */ this.channelDebug_ = new goog.net.ChannelDebug(); + + /** + * Parser for a response payload. Defaults to use + * {@code goog.json.unsafeParse}. The parser should return an array. + * @type {!goog.string.Parser} + * @private + */ + this.parser_ = new goog.json.EvalJsonProcessor(null, true); }; @@ -117,9 +129,10 @@ goog.net.BrowserChannel = function(clientVersion) { * Simple container class for a (mapId, map) pair. * @param {number} mapId The id for this map. * @param {Object|goog.structs.Map} map The map itself. + * @param {Object=} opt_context The context associated with the map. * @constructor */ -goog.net.BrowserChannel.QueuedMap = function(mapId, map) { +goog.net.BrowserChannel.QueuedMap = function(mapId, map, opt_context) { /** * The id for this map. * @type {number} @@ -131,6 +144,12 @@ goog.net.BrowserChannel.QueuedMap = function(mapId, map) { * @type {Object|goog.structs.Map} */ this.map = map; + + /** + * The context for the map. + * @type {Object} + */ + this.context = opt_context || null; }; @@ -344,6 +363,61 @@ goog.net.BrowserChannel.prototype.backChannelAttemptId_; /** + * The base part of the time before firing next retry request. Default is 5 + * seconds. Note that a random delay is added (see {@link retryDelaySeedMs_}) + * for all retries, and linear backoff is applied to the sum for subsequent + * retries. + * @type {number} + * @private + */ +goog.net.BrowserChannel.prototype.baseRetryDelayMs_ = 5 * 1000; + + +/** + * A random time between 0 and this number of MS is added to the + * {@link baseRetryDelayMs_}. Default is 10 seconds. + * @type {number} + * @private + */ +goog.net.BrowserChannel.prototype.retryDelaySeedMs_ = 10 * 1000; + + +/** + * Maximum number of attempts to connect to the server for forward channel + * requests. Defaults to 2. + * @type {number} + * @private + */ +goog.net.BrowserChannel.prototype.forwardChannelMaxRetries_ = 2; + + +/** + * The timeout in milliseconds for a forward channel request. Defaults to 20 + * seconds. Note that part of this timeout can be randomized. + * @type {number} + * @private + */ +goog.net.BrowserChannel.prototype.forwardChannelRequestTimeoutMs_ = 20 * 1000; + + +/** + * A throttle time in ms for readystatechange events for the backchannel. + * Useful for throttling when ready state is INTERACTIVE (partial data). + * + * This throttle is useful if the server sends large data chunks down the + * backchannel. It prevents examining XHR partial data on every + * readystate change event. This is useful because large chunks can + * trigger hundreds of readystatechange events, each of which takes ~5ms + * or so to handle, in turn making the UI unresponsive for a significant period. + * + * If set to zero no throttle is used. + * @type {number} + * @private + */ +goog.net.BrowserChannel.prototype.readyStateChangeThrottleMs_ = 0; + + +/** * The latest protocol version that this class supports. We request this version * from the server when opening the connection. Should match * com.google.net.browserchannel.BrowserChannel.LATEST_CHANNEL_VERSION. @@ -383,14 +457,6 @@ goog.net.BrowserChannel.State = { /** - * Maximum number of attempts to connect to the server for forward channel - * requests. - * @type {number} - */ -goog.net.BrowserChannel.FORWARD_CHANNEL_MAX_RETRIES = 2; - - -/** * The timeout in milliseconds for a forward channel request. * @type {number} */ @@ -406,22 +472,6 @@ goog.net.BrowserChannel.BACK_CHANNEL_MAX_RETRIES = 3; /** - * Default timeout in MS before the initial retry. Subsequent retries will be - * slower. - * @type {number} - */ -goog.net.BrowserChannel.RETRY_DELAY_MS = 5 * 1000; - - -/** - * We will add a random time between 0 and this number of MS to retries to - * the retry time for this request. - * @type {number} - */ -goog.net.BrowserChannel.RETRY_DELAY_SEED = 10 * 1000; - - -/** * A number in MS of how long we guess the maxmium amount of time a round trip * to the server should take. In the future this could be substituted with a * real measurement of the RTT. @@ -471,7 +521,10 @@ goog.net.BrowserChannel.Error = { BAD_DATA: 10, /** An error due to a response that doesn't start with the magic cookie. */ - BAD_RESPONSE: 11 + BAD_RESPONSE: 11, + + /** ActiveX is blocked by the machine's admin settings. */ + ACTIVE_X_BLOCKED: 12 }; @@ -587,6 +640,52 @@ goog.inherits(goog.net.BrowserChannel.TimingEvent, goog.events.Event); /** + * The type of event that occurs every time some information about how reachable + * the server is is discovered. + */ +goog.net.BrowserChannel.Event.SERVER_REACHABILITY_EVENT = + 'serverreachability'; + + +/** + * Types of events which reveal information about the reachability of the + * server. + * @enum {number} + */ +goog.net.BrowserChannel.ServerReachability = { + REQUEST_MADE: 1, + REQUEST_SUCCEEDED: 2, + REQUEST_FAILED: 3, + BACK_CHANNEL_ACTIVITY: 4 +}; + + + +/** + * Event class for goog.net.BrowserChannel.Event.SERVER_REACHABILITY_EVENT. + * + * @param {goog.events.EventTarget} target The stat event target for + the browser channel. + * @param {goog.net.BrowserChannel.ServerReachability} reachabilityType The + * reachability event type. + * @constructor + * @extends {goog.events.Event} + */ +goog.net.BrowserChannel.ServerReachabilityEvent = function(target, + reachabilityType) { + goog.events.Event.call(this, + goog.net.BrowserChannel.Event.SERVER_REACHABILITY_EVENT, target); + + /** + * @type {goog.net.BrowserChannel.ServerReachability} + */ + this.reachabilityType = reachabilityType; +}; +goog.inherits(goog.net.BrowserChannel.ServerReachabilityEvent, + goog.events.Event); + + +/** * Enum that identifies events for statistics that are interesting to track. * TODO(user) - Change name not to use Event or use EventTarget * @enum {number} @@ -672,7 +771,16 @@ goog.net.BrowserChannel.Stat = { * Event indicating that we have determined that our hanging GET is not * receiving data when it should be. Thus it is dead dead and will be retried. */ - BACKCHANNEL_DEAD: 20 + BACKCHANNEL_DEAD: 20, + + /** + * The browser declared itself offline during the lifetime of a request, or + * was offline when a request was initially made. + */ + BROWSER_OFFLINE: 21, + + /** ActiveX is blocked by the machine's admin settings. */ + ACTIVE_X_BLOCKED: 22 }; @@ -713,7 +821,9 @@ goog.net.BrowserChannel.prototype.getChannelDebug = function() { */ goog.net.BrowserChannel.prototype.setChannelDebug = function( channelDebug) { - this.channelDebug_ = channelDebug; + if (goog.isDefAndNotNull(channelDebug)) { + this.channelDebug_ = channelDebug; + } }; @@ -769,8 +879,8 @@ goog.net.BrowserChannel.endExecutionHook_ = function() { }; * @param {number=} opt_retryId The retry id for this request. * @return {goog.net.ChannelRequest} The created channel request. */ -goog.net.BrowserChannel.createChannelRequest = function( - channel, channelDebug, opt_sessionId, opt_requestId, opt_retryId) { +goog.net.BrowserChannel.createChannelRequest = function(channel, channelDebug, + opt_sessionId, opt_requestId, opt_retryId) { return new goog.net.ChannelRequest( channel, channelDebug, @@ -785,20 +895,20 @@ goog.net.BrowserChannel.createChannelRequest = function( * * @param {string} testPath The path for the test connection. * @param {string} channelPath The path for the channel connection. - * @param {Object} extraParams Extra parameter keys and values to add to the - * requests. + * @param {Object=} opt_extraParams Extra parameter keys and values to add to + * the requests. * @param {string=} opt_oldSessionId Session ID from a previous session. * @param {number=} opt_oldArrayId The last array ID from a previous session. */ goog.net.BrowserChannel.prototype.connect = function(testPath, channelPath, - extraParams, opt_oldSessionId, opt_oldArrayId) { + opt_extraParams, opt_oldSessionId, opt_oldArrayId) { this.channelDebug_.debug('connect()'); goog.net.BrowserChannel.notifyStatEvent( goog.net.BrowserChannel.Stat.CONNECT_ATTEMPT); this.path_ = channelPath; - this.extraParams_ = extraParams || {}; + this.extraParams_ = opt_extraParams || {}; // Attach parameters about the previous session if reconnecting. if (opt_oldSessionId && goog.isDef(opt_oldArrayId)) { @@ -831,8 +941,9 @@ goog.net.BrowserChannel.prototype.disconnect = function() { var request = goog.net.BrowserChannel.createChannelRequest( this, this.channelDebug_, this.sid_, rid); request.sendUsingImgTag(uri); - this.onClose_(); } + + this.onClose_(); }; @@ -860,6 +971,7 @@ goog.net.BrowserChannel.prototype.connectTest_ = function(testPath) { this.connectionTest_ = new goog.net.BrowserTestChannel( this, this.channelDebug_); this.connectionTest_.setExtraHeaders(this.extraHeaders_); + this.connectionTest_.setParser(this.parser_); this.connectionTest_.connect(testPath); }; @@ -933,6 +1045,18 @@ goog.net.BrowserChannel.prototype.setExtraHeaders = function(extraHeaders) { /** + * Sets the throttle for handling onreadystatechange events for the request. + * + * @param {number} throttle The throttle in ms. A value of zero indicates + * no throttle. + */ +goog.net.BrowserChannel.prototype.setReadyStateChangeThrottle = function( + throttle) { + this.readyStateChangeThrottleMs_ = throttle; +}; + + +/** * Returns the handler used for channel callback events. * * @return {goog.net.BrowserChannel.Handler} The handler. @@ -1016,8 +1140,9 @@ goog.net.BrowserChannel.prototype.setAllowChunkedMode = * suitable for the wire and then reconstituted as a Map data structure that * the server can process. * @param {Object|goog.structs.Map} map The map to send. + * @param {?Object=} opt_context The context associated with the map. */ -goog.net.BrowserChannel.prototype.sendMap = function(map) { +goog.net.BrowserChannel.prototype.sendMap = function(map, opt_context) { if (this.state_ == goog.net.BrowserChannel.State.CLOSED) { throw Error('Invalid operation: sending map when state is closed'); } @@ -1034,7 +1159,8 @@ goog.net.BrowserChannel.prototype.sendMap = function(map) { } this.outgoingMaps_.push( - new goog.net.BrowserChannel.QueuedMap(this.nextMapId_++, map)); + new goog.net.BrowserChannel.QueuedMap(this.nextMapId_++, map, + opt_context)); if (this.state_ == goog.net.BrowserChannel.State.OPENING || this.state_ == goog.net.BrowserChannel.State.OPENED) { this.ensureForwardChannel_(); @@ -1078,8 +1204,28 @@ goog.net.BrowserChannel.prototype.setFailFast = function(failFast) { * in fail-fast mode. */ goog.net.BrowserChannel.prototype.getForwardChannelMaxRetries = function() { - return this.failFast_ ? - 0 : goog.net.BrowserChannel.FORWARD_CHANNEL_MAX_RETRIES; + return this.failFast_ ? 0 : this.forwardChannelMaxRetries_; +}; + + +/** + * Sets the maximum number of attempts to connect to the server for forward + * channel requests. + * @param {number} retries The maximum number of attempts. + */ +goog.net.BrowserChannel.prototype.setForwardChannelMaxRetries = + function(retries) { + this.forwardChannelMaxRetries_ = retries; +}; + + +/** + * Sets the timeout for a forward channel request. + * @param {number} timeoutMs The timeout in milliseconds. + */ +goog.net.BrowserChannel.prototype.setForwardChannelRequestTimeout = + function(timeoutMs) { + this.forwardChannelRequestTimeoutMs_ = timeoutMs; }; @@ -1138,6 +1284,17 @@ goog.net.BrowserChannel.prototype.hasOutstandingRequests = function() { /** + * Sets a new parser for the response payload. A custom parser may be set to + * avoid using eval(), for example. By default, the parser uses + * {@code goog.json.unsafeParse}. + * @param {!goog.string.Parser} parser Parser. + */ +goog.net.BrowserChannel.prototype.setParser = function(parser) { + this.parser_ = parser; +}; + + +/** * Returns the number of outstanding requests. * @return {number} The number of outstanding requests to the server. * @private @@ -1331,9 +1488,8 @@ goog.net.BrowserChannel.prototype.makeForwardChannelRequest_ = // randomize from 50%-100% of the forward channel timeout to avoid // a big hit if servers happen to die at once. request.setTimeout( - Math.round(goog.net.BrowserChannel.FORWARD_CHANNEL_RETRY_TIMEOUT * 0.50) + - Math.round(goog.net.BrowserChannel.FORWARD_CHANNEL_RETRY_TIMEOUT * 0.50 * - Math.random())); + Math.round(this.forwardChannelRequestTimeoutMs_ * 0.50) + + Math.round(this.forwardChannelRequestTimeoutMs_ * 0.50 * Math.random())); this.forwardChannelRequest_ = request; request.xmlHttpPost(uri, requestText, true); }; @@ -1493,6 +1649,8 @@ goog.net.BrowserChannel.prototype.startBackChannel_ = function() { 'rpc', this.backChannelAttemptId_); this.backChannelRequest_.setExtraHeaders(this.extraHeaders_); + this.backChannelRequest_.setReadyStateChangeThrottle( + this.readyStateChangeThrottleMs_); var uri = this.backChannelUri_.clone(); uri.setParameterValue('RID', 'rpc'); uri.setParameterValue('SID', this.sid_); @@ -1596,12 +1754,12 @@ goog.net.BrowserChannel.prototype.onRequestData = if (this.channelVersion_ > 7) { var response; try { - response = (/** @type {Array} */ goog.json.unsafeParse(responseText)); + response = this.parser_.parse(responseText); } catch (ex) { response = null; } if (goog.isArray(response) && response.length == 3) { - this.handlePostResponse_(response); + this.handlePostResponse_(/** @type {Array} */ (response)); } else { this.channelDebug_.debug('Bad POST response data returned'); this.signalError_(goog.net.BrowserChannel.Error.BAD_RESPONSE); @@ -1616,7 +1774,9 @@ goog.net.BrowserChannel.prototype.onRequestData = this.clearDeadBackchannelTimer_(); } if (!goog.string.isEmpty(responseText)) { - this.onInput_(/** @type {Array} */ (goog.json.unsafeParse(responseText))); + var response = this.parser_.parse(responseText); + goog.asserts.assert(goog.isArray(response)); + this.onInput_(/** @type {Array} */ (response)); } } }; @@ -1765,6 +1925,7 @@ goog.net.BrowserChannel.prototype.clearDeadBackchannelTimer_ = function() { goog.net.BrowserChannel.isFatalError_ = function(error, statusCode) { return error == goog.net.ChannelRequest.Error.UNKNOWN_SESSION_ID || + error == goog.net.ChannelRequest.Error.ACTIVE_X_BLOCKED || (error == goog.net.ChannelRequest.Error.STATUS && statusCode > 0); }; @@ -1804,6 +1965,7 @@ goog.net.BrowserChannel.prototype.onRequestComplete = goog.now() - request.getRequestStartTime(), this.forwardChannelRetryCount_); this.ensureForwardChannel_(); + this.onSuccess_(); this.pendingMaps_.length = 0; } else { // i.e., back-channel this.ensureBackChannel_(); @@ -1850,6 +2012,9 @@ goog.net.BrowserChannel.prototype.onRequestComplete = case goog.net.ChannelRequest.Error.UNKNOWN_SESSION_ID: this.signalError_(goog.net.BrowserChannel.Error.UNKNOWN_SESSION_ID); break; + case goog.net.ChannelRequest.Error.ACTIVE_X_BLOCKED: + this.signalError_(goog.net.BrowserChannel.Error.ACTIVE_X_BLOCKED); + break; default: this.signalError_(goog.net.BrowserChannel.Error.REQUEST_FAILED); break; @@ -1863,8 +2028,8 @@ goog.net.BrowserChannel.prototype.onRequestComplete = * @private */ goog.net.BrowserChannel.prototype.getRetryTime_ = function(retryCount) { - var retryTime = goog.net.BrowserChannel.RETRY_DELAY_MS + - Math.floor(Math.random() * goog.net.BrowserChannel.RETRY_DELAY_SEED); + var retryTime = this.baseRetryDelayMs_ + + Math.floor(Math.random() * this.retryDelaySeedMs_); if (!this.isActive()) { this.channelDebug_.debug('Inactive channel'); retryTime = @@ -1877,6 +2042,18 @@ goog.net.BrowserChannel.prototype.getRetryTime_ = function(retryCount) { /** + * @param {number} baseDelayMs The base part of the retry delay, in ms. + * @param {number} delaySeedMs A random delay between 0 and this is added to + * the base part. + */ +goog.net.BrowserChannel.prototype.setRetryDelay = function(baseDelayMs, + delaySeedMs) { + this.baseRetryDelayMs_ = baseDelayMs; + this.retryDelaySeedMs_ = delaySeedMs; +}; + + +/** * Processes the data returned by the server. * @param {Array} respArray The response array returned by the server. * @private @@ -2001,6 +2178,17 @@ goog.net.BrowserChannel.prototype.testGoogleComCallback_ = function(networkUp) { /** + * Called when messages have been successfully sent from the queue. + * @private + */ +goog.net.BrowserChannel.prototype.onSuccess_ = function() { + if (this.handler_) { + this.handler_.channelSuccess(this, this.pendingMaps_); + } +}; + + +/** * Called when we've determined the final error for a channel. It closes the * notifiers the handler of the error and closes the channel. * @param {goog.net.BrowserChannel.Error} error The error code for the failure. @@ -2197,6 +2385,20 @@ goog.net.BrowserChannel.getStatEventTarget = function() { /** + * Notify the channel that a particular fine grained network event has occurred. + * Should be considered package-private. + * @param {goog.net.BrowserChannel.ServerReachability} reachabilityType The + * reachability event type. + */ +goog.net.BrowserChannel.prototype.notifyServerReachabilityEvent = function( + reachabilityType) { + var target = goog.net.BrowserChannel.statEventTarget_; + target.dispatchEvent(new goog.net.BrowserChannel.ServerReachabilityEvent( + target, reachabilityType)); +}; + + +/** * Helper function to call the stat event callback. * @param {goog.net.BrowserChannel.Stat} stat The stat. */ @@ -2229,7 +2431,9 @@ goog.net.BrowserChannel.notifyTimingEvent = function(size, rtt, retries) { * Currently, we only use secondary domains when using Trident's ActiveXObject, * because it supports cross-domain requests out of the box. Even if we wanted * to use secondary domains on Gecko/Webkit, they wouldn't work due to - * security restrictions on cross-origin XHRs. + * security restrictions on cross-origin XHRs. Note that in IE10 we no longer + * use ActiveX since it's not supported in Metro mode and IE10 supports XHR + * streaming. * * If you need to use secondary domains on other browsers, you'll need * to override this method in a subclass, and make sure that those browsers @@ -2239,7 +2443,7 @@ goog.net.BrowserChannel.notifyTimingEvent = function(size, rtt, retries) { * @see http://code.google.com/p/closure-library/issues/detail?id=339 */ goog.net.BrowserChannel.prototype.shouldUseSecondaryDomains = function() { - return goog.userAgent.IE; + return !goog.net.ChannelRequest.supportsXhrStreaming(); }; @@ -2385,6 +2589,20 @@ goog.net.BrowserChannel.Handler.prototype.channelHandleArray = /** + * Indicates maps were successfully sent on the BrowserChannel. + * + * @param {goog.net.BrowserChannel} browserChannel The browser channel. + * @param {Array.<goog.net.BrowserChannel.QueuedMap>} deliveredMaps The + * array of maps that have been delivered to the server. This is a direct + * reference to the internal BrowserChannel array, so a copy should be made + * if the caller desires a reference to the data. + */ +goog.net.BrowserChannel.Handler.prototype.channelSuccess = + function(browserChannel, deliveredMaps) { +}; + + +/** * Indicates an error occurred on the BrowserChannel. * * @param {goog.net.BrowserChannel} browserChannel The browser channel. diff --git a/contexts/data/lib/closure-library/closure/goog/net/browserchannel_test.html b/contexts/data/lib/closure-library/closure/goog/net/browserchannel_test.html index 89bce9e..1fc0c5e 100644 --- a/contexts/data/lib/closure-library/closure/goog/net/browserchannel_test.html +++ b/contexts/data/lib/closure-library/closure/goog/net/browserchannel_test.html @@ -11,8 +11,8 @@ See the COPYING file for details. <head> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>Closure Unit Tests - goog.net.BrowserChannel</title> -<script type="text/javascript" src="../base.js"></script> -<script type="text/javascript"> +<script src="../base.js"></script> +<script> goog.require('goog.Timer'); goog.require('goog.dom'); goog.require('goog.functions'); @@ -23,14 +23,14 @@ See the COPYING file for details. goog.require('goog.string.StringBuffer'); goog.require('goog.structs.Map'); goog.require('goog.testing.MockClock'); + goog.require('goog.testing.PropertyReplacer'); + goog.require('goog.testing.recordFunction'); goog.require('goog.testing.asserts'); goog.require('goog.testing.jsunit'); </script> </head> <body> - -<!-- Define unit tests. --> -<script type="text/javascript" > +<script> /** * Delay between a network failure and the next network request. @@ -42,10 +42,12 @@ var RETRY_TIME = 1000; */ var ALL_DAY_MS = 1000 * 60 * 60 * 24; +var stubs = new goog.testing.PropertyReplacer(); + var browserChannel; +var deliveredMaps; var handler; var mockClock; -var sb; var gotError; var numStatEvents; var lastStatEvent; @@ -56,20 +58,38 @@ var lastPostRetryCount; // Set to true to see the channel debug output in the browser window. var debug = false; +// Debug message to print out when debug is true. +var debugMessage = ''; function debugToWindow(message) { if (debug) { - sb.append(message + '<br>'); - goog.dom.getElement('debug').innerHTML = sb.toString(); + debugMessage += message + '<br>'; + goog.dom.getElement('debug').innerHTML = debugMessage; } } /** + * Stubs goog.net.tmpnetwork to always time out. It maintains the + * contract given by goog.net.tmpnetwork.testGoogleCom, but always + * times out (calling callback(false)). + * + * stubTmpnetwork should be called in tests that require it before + * a call to testGoogleCom happens. It is reset at tearDown. + */ +function stubTmpnetwork() { + stubs.set(goog.net.tmpnetwork, 'testLoadImage', + function(url, timeout, callback) { + goog.Timer.callOnce(goog.partial(callback, false), timeout); + }); +} + + +/** * Mock ChannelRequest. + * @constructor */ -function MockChannelRequest() {} -MockChannelRequest = function(channel, channelDebug, opt_sessionId, +var MockChannelRequest = function(channel, channelDebug, opt_sessionId, opt_requestId, opt_retryId) { this.channel_ = channel; this.channelDebug_ = channelDebug; @@ -92,6 +112,9 @@ MockChannelRequest.prototype.setExtraHeaders = function(extraHeaders) {}; MockChannelRequest.prototype.setTimeout = function(timeout) {}; +MockChannelRequest.prototype.setReadyStateChangeThrottle = + function(throttle) {}; + MockChannelRequest.prototype.xmlHttpPost = function(uri, postData, decodeChunks) { this.channelDebug_.debug('---> POST: ' + uri + ', ' + postData + ', ' + @@ -156,7 +179,6 @@ function setUpPage() { return new MockChannelRequest( channel, channelDebug, opt_sessionId, opt_requestId, opt_retryId); }; - sb = new goog.string.StringBuffer(); // Mock out the stat notification code. goog.net.BrowserChannel.notifyStatEvent = function(stat) { @@ -188,6 +210,9 @@ function setUp() { handler.channelError = function(channel, error) { gotError = true; }; + handler.channelSuccess = function(channel, maps) { + deliveredMaps = goog.array.clone(maps); + }; handler.channelClosed = function( channel, opt_pendingMaps, opt_undeliveredMaps) { // Mock out the handler, and let it set a formatted user readable string @@ -222,6 +247,7 @@ function setUp() { function tearDown() { mockClock.dispose(); + stubs.reset(); debugToWindow('<hr>'); } @@ -235,7 +261,9 @@ function formatArrayOfMaps(arrayOfMaps) { var map = arrayOfMaps[i]; var keys = map.map.getKeys(); for (var j = 0; j < keys.length; j++) { - result.push(keys[j] + ':' + map.map.get(keys[j])); + var tmp = keys[j] + ':' + map.map.get(keys[j]) + (map.context ? + ':' + map.context : ''); + result.push(tmp); } } return result.join(', '); @@ -267,15 +295,27 @@ function testFormatArrayOfMaps() { b.push(new goog.net.BrowserChannel.QueuedMap(0, map3)); assertEquals('k1:v1, k2:v2, k3:v3, k4:v4, k5:v5, k6:v6', formatArrayOfMaps(b)); + + // One map with a context. + var c = []; + c.push(new goog.net.BrowserChannel.QueuedMap(0, map1, 'c1')); + assertEquals('k1:v1:c1, k2:v2:c1', + formatArrayOfMaps(c)); } -function connect(opt_serverVersion, opt_hostPrefix, opt_uriPrefix) { +function connectForwardChannel( + opt_serverVersion, opt_hostPrefix, opt_uriPrefix) { var uriPrefix = opt_uriPrefix || ''; browserChannel.connect(uriPrefix + '/test', uriPrefix + '/bind', null); mockClock.tick(0); completeTestConnection(); completeForwardChannel(opt_serverVersion, opt_hostPrefix); +} + + +function connect(opt_serverVersion, opt_hostPrefix, opt_uriPrefix) { + connectForwardChannel(opt_serverVersion, opt_hostPrefix, opt_uriPrefix); completeBackChannel(); } @@ -411,10 +451,20 @@ function responseUnknownSessionId() { } -function sendMap(key, value) { +function responseActiveXBlocked() { + browserChannel.backChannelRequest_.lastError_ = + goog.net.ChannelRequest.Error.ACTIVE_X_BLOCKED; + browserChannel.backChannelRequest_.successful_ = false; + browserChannel.onRequestComplete( + browserChannel.backChannelRequest_); + mockClock.tick(0); +} + + +function sendMap(key, value, opt_context) { var map = new goog.structs.Map(); map.set(key, value); - browserChannel.sendMap(map); + browserChannel.sendMap(map, opt_context); mockClock.tick(0); } @@ -509,6 +559,7 @@ function testSendMap() { sendMap('foo', 'bar'); responseVersion7(); assertEquals(2, numTimingEvents); + assertEquals('foo:bar', formatArrayOfMaps(deliveredMaps)); } @@ -516,8 +567,10 @@ function testSendMap_twice() { connect(); sendMap('foo1', 'bar1'); responseVersion7(); + assertEquals('foo1:bar1', formatArrayOfMaps(deliveredMaps)); sendMap('foo2', 'bar2'); responseVersion7(); + assertEquals('foo2:bar2', formatArrayOfMaps(deliveredMaps)); } @@ -610,6 +663,8 @@ function testTimingEvent(){ * reports an error, and prevents another request from firing. */ function testSetFailFastWhileWaitingForRetry() { + stubTmpnetwork(); + connect(); assertEquals(1, numTimingEvents); @@ -637,12 +692,13 @@ function testSetFailFastWhileWaitingForRetry() { assertEquals(1, browserChannel.forwardChannelRetryCount_); assertTrue(gotError); + assertEquals(0, deliveredMaps.length); // We get the error immediately before starting to ping google.com. // Simulate that timing out. We should get a network error in addition to the // initial failure. gotError = false; mockClock.tick(goog.net.tmpnetwork.GOOGLECOM_TIMEOUT); - assertTrue(gotError); + assertTrue('No error after tmpnetwork ping timed out.', gotError); // Make sure no more retry timers are firing. mockClock.tick(ALL_DAY_MS); @@ -658,6 +714,8 @@ function testSetFailFastWhileWaitingForRetry() { * reports an error, and prevents another request from firing. */ function testSetFailFastWhileRetryXhrIsInFlight() { + stubTmpnetwork(); + connect(); assertEquals(1, numTimingEvents); @@ -702,7 +760,7 @@ function testSetFailFastWhileRetryXhrIsInFlight() { // Simulate that timing out. We should get a network error in addition to the gotError = false; mockClock.tick(goog.net.tmpnetwork.GOOGLECOM_TIMEOUT); - assertTrue(gotError); + assertTrue('No error after tmpnetwork ping timed out.', gotError); // Make sure no more retry timers are firing. mockClock.tick(ALL_DAY_MS); @@ -717,6 +775,8 @@ function testSetFailFastWhileRetryXhrIsInFlight() { * Makes sure that setting fail fast while not retrying doesn't cause a failure. */ function testSetFailFastAtRetryCount() { + stubTmpnetwork(); + connect(); assertEquals(1, numTimingEvents); @@ -744,7 +804,7 @@ function testSetFailFastAtRetryCount() { // initial failure. gotError = false; mockClock.tick(goog.net.tmpnetwork.GOOGLECOM_TIMEOUT); - assertTrue(gotError); + assertTrue('No error after tmpnetwork ping timed out.', gotError); // Make sure no more retry timers are firing. mockClock.tick(ALL_DAY_MS); @@ -756,6 +816,8 @@ function testSetFailFastAtRetryCount() { function testRequestFailedClosesChannel() { + stubTmpnetwork(); + connect(); assertEquals(1, numTimingEvents); @@ -774,6 +836,8 @@ function testRequestFailedClosesChannel() { function testStatEventReportedOnlyOnce() { + stubTmpnetwork(); + connect(); sendMap('foo', 'bar'); numStatEvents = 0; @@ -789,7 +853,25 @@ function testStatEventReportedOnlyOnce() { } +function testActiveXBlockedEventReportedOnlyOnce() { + stubTmpnetwork(); + + connectForwardChannel(); + numStatEvents = 0; + lastStatEvent = null; + responseActiveXBlocked(); + + assertEquals(1, numStatEvents); + assertEquals(goog.net.BrowserChannel.Stat.ERROR_OTHER, lastStatEvent); + + mockClock.tick(goog.net.tmpnetwork.GOOGLECOM_TIMEOUT); + assertEquals('No new stat events should be reported.', 1, numStatEvents); +} + + function testStatEventReportedOnlyOnce_onNetworkUp() { + stubTmpnetwork(); + connect(); sendMap('foo', 'bar'); numStatEvents = 0; @@ -809,6 +891,8 @@ function testStatEventReportedOnlyOnce_onNetworkUp() { function testStatEventReportedOnlyOnce_onNetworkDown() { + stubTmpnetwork(); + connect(); sendMap('foo', 'bar'); numStatEvents = 0; @@ -895,19 +979,19 @@ function testUndeliveredMaps_clearsPendingMapsAfterNotifying() { } -function testUndeliveredMaps_notifiesWhenNoResponseReceived() { +function testUndeliveredMaps_notifiesWithContext() { connect(); // First send two messages that succeed. - sendMap('foo1', 'bar1'); + sendMap('foo1', 'bar1', 'context1'); responseVersion7(); - sendMap('foo2', 'bar2'); + sendMap('foo2', 'bar2', 'context2'); responseVersion7(); // Pretend the server hangs and no longer responds. - sendMap('foo3', 'bar3'); - sendMap('foo4', 'bar4'); - sendMap('foo5', 'bar5'); + sendMap('foo3', 'bar3', 'context3'); + sendMap('foo4', 'bar4', 'context4'); + sendMap('foo5', 'bar5', 'context5'); // Give up. disconnect(); @@ -915,8 +999,9 @@ function testUndeliveredMaps_notifiesWhenNoResponseReceived() { // Assert that we are informed of any undelivered messages; both about // #3 that was sent but which we don't know if the server received, and // #4 and #5 which remain in the outgoing maps and have not yet been sent. - assertEquals('foo3:bar3', handler.pendingMapsString); - assertEquals('foo4:bar4, foo5:bar5', handler.undeliveredMapsString); + assertEquals('foo3:bar3:context3', handler.pendingMapsString); + assertEquals('foo4:bar4:context4, foo5:bar5:context5', + handler.undeliveredMapsString); } @@ -937,6 +1022,8 @@ function testUndeliveredMaps_serviceUnavailable() { function testUndeliveredMaps_onPingTimeout() { + stubTmpnetwork(); + connect(); // Send a message. @@ -1194,6 +1281,30 @@ function testPathWithHost() { assertEquals(browserChannel.forwardChannelUri_.getDomain(), 'example.com'); } +function testSetParser() { + var recordUnsafeParse = goog.testing.recordFunction( + goog.json.unsafeParse); + var parser = {}; + parser.parse = recordUnsafeParse; + browserChannel.setParser(parser); + + connect(); + assertEquals(3, recordUnsafeParse.getCallCount()); + + var call3 = recordUnsafeParse.popLastCall(); + var call2 = recordUnsafeParse.popLastCall(); + var call1 = recordUnsafeParse.popLastCall(); + + assertEquals(1, call1.getArguments().length); + assertEquals('["b"]', call1.getArgument(0)); + + assertEquals(1, call2.getArguments().length); + assertEquals('[[0,["c","1234567890ABCDEF",null]]]', call2.getArgument(0)); + + assertEquals(1, call3.getArguments().length); + assertEquals('[[1,["foo"]]]', call3.getArgument(0)); +} + </script> <div id="debug" style="font-size: small"></div> </body> diff --git a/contexts/data/lib/closure-library/closure/goog/net/browsertestchannel.js b/contexts/data/lib/closure-library/closure/goog/net/browsertestchannel.js index 6a66de7..cfc9257 100644 --- a/contexts/data/lib/closure-library/closure/goog/net/browsertestchannel.js +++ b/contexts/data/lib/closure-library/closure/goog/net/browsertestchannel.js @@ -25,10 +25,11 @@ goog.provide('goog.net.BrowserTestChannel'); -goog.require('goog.json'); +goog.require('goog.json.EvalJsonProcessor'); goog.require('goog.net.ChannelRequest'); goog.require('goog.net.ChannelRequest.Error'); goog.require('goog.net.tmpnetwork'); +goog.require('goog.string.Parser'); goog.require('goog.userAgent'); @@ -56,6 +57,14 @@ goog.net.BrowserTestChannel = function(channel, channelDebug) { * @private */ this.channelDebug_ = channelDebug; + + /** + * Parser for a response payload. Defaults to use + * {@code goog.json.unsafeParse}. The parser should return an array. + * @type {goog.string.Parser} + * @private + */ + this.parser_ = new goog.json.EvalJsonProcessor(null, true); }; @@ -229,6 +238,17 @@ goog.net.BrowserTestChannel.prototype.setExtraHeaders = function(extraHeaders) { /** + * Sets a new parser for the response payload. A custom parser may be set to + * avoid using eval(), for example. + * By default, the parser uses {@code goog.json.unsafeParse}. + * @param {!goog.string.Parser} parser Parser. + */ +goog.net.BrowserTestChannel.prototype.setParser = function(parser) { + this.parser_ = parser; +}; + + +/** * Starts the test channel. This initiates connections to the server. * * @param {string} path The relative uri for the test connection. @@ -270,6 +290,8 @@ goog.net.BrowserTestChannel.prototype.checkBlocked_ = function() { goog.bind(this.checkBlockedCallback_, this), goog.net.BrowserTestChannel.BLOCKED_RETRIES_, goog.net.BrowserTestChannel.BLOCKED_PAUSE_BETWEEN_RETRIES_); + this.notifyServerReachabilityEvent( + goog.net.BrowserChannel.ServerReachability.REQUEST_MADE); }; @@ -289,6 +311,14 @@ goog.net.BrowserTestChannel.prototype.checkBlockedCallback_ = function( goog.net.BrowserChannel.Stat.CHANNEL_BLOCKED); this.channel_.testConnectionBlocked(this); } + + // We don't dispatch a REQUEST_FAILED server reachability event when the + // block request fails, as such a failure is not a good signal that the + // server has actually become unreachable. + if (succeeded) { + this.notifyServerReachabilityEvent( + goog.net.BrowserChannel.ServerReachability.REQUEST_SUCCEEDED); + } }; @@ -375,7 +405,7 @@ goog.net.BrowserTestChannel.prototype.onRequestData = } /** @preserveTry */ try { - var respArray = goog.json.unsafeParse(responseText); + var respArray = this.parser_.parse(responseText); } catch (e) { this.channelDebug_.dumpException(e); this.channel_.testConnectionFailure(this, @@ -539,3 +569,14 @@ goog.net.BrowserTestChannel.prototype.checkForEarlyNonBuffered_ = return goog.net.ChannelRequest.supportsXhrStreaming() || ms < goog.net.BrowserTestChannel.MIN_TIME_EXPECTED_BETWEEN_DATA_; }; + + +/** + * Notifies the channel of a fine grained network event. + * @param {goog.net.BrowserChannel.ServerReachability} reachabilityType The + * reachability event type. + */ +goog.net.BrowserTestChannel.prototype.notifyServerReachabilityEvent = + function(reachabilityType) { + this.channel_.notifyServerReachabilityEvent(reachabilityType); +}; diff --git a/contexts/data/lib/closure-library/closure/goog/net/bulkloader.js b/contexts/data/lib/closure-library/closure/goog/net/bulkloader.js index 70afa6f..777c55d 100644 --- a/contexts/data/lib/closure-library/closure/goog/net/bulkloader.js +++ b/contexts/data/lib/closure-library/closure/goog/net/bulkloader.js @@ -66,7 +66,7 @@ goog.net.BulkLoader.prototype.logger_ = /** - * Gets the response texts. + * Gets the response texts, in order. * @return {Array.<string>} The response texts. */ goog.net.BulkLoader.prototype.getResponseTexts = function() { @@ -75,6 +75,15 @@ goog.net.BulkLoader.prototype.getResponseTexts = function() { /** + * Gets the request Uris. + * @return {Array.<string>} The request URIs, in order. + */ +goog.net.BulkLoader.prototype.getRequestUris = function() { + return this.helper_.getUris(); +}; + + +/** * Starts the process of loading the URIs. */ goog.net.BulkLoader.prototype.load = function() { diff --git a/contexts/data/lib/closure-library/closure/goog/net/bulkloader_test.html b/contexts/data/lib/closure-library/closure/goog/net/bulkloader_test.html index 7b904fd..a394bf6 100644 --- a/contexts/data/lib/closure-library/closure/goog/net/bulkloader_test.html +++ b/contexts/data/lib/closure-library/closure/goog/net/bulkloader_test.html @@ -177,6 +177,7 @@ See the COPYING file for details. function testBulkLoaderLoadSuccess() { var uris = ['a', 'b', 'c']; var bulkLoader = getSuccessfulBulkLoader(uris); + assertArrayEquals(uris, bulkLoader.getRequestUris()); bulkLoader.load(); diff --git a/contexts/data/lib/closure-library/closure/goog/net/channeldebug.js b/contexts/data/lib/closure-library/closure/goog/net/channeldebug.js index b31f089..f216a76 100644 --- a/contexts/data/lib/closure-library/closure/goog/net/channeldebug.js +++ b/contexts/data/lib/closure-library/closure/goog/net/channeldebug.js @@ -54,6 +54,15 @@ goog.net.ChannelDebug.prototype.getLogger = function() { /** + * Logs that the browser went offline during the lifetime of a request. + * @param {goog.Uri} url The URL being requested. + */ +goog.net.ChannelDebug.prototype.browserOfflineResponse = function(url) { + this.info('BROWSER_OFFLINE: ' + url); +}; + + +/** * Logs an XmlHttp request.. * @param {string} verb The request type (GET/POST). * @param {goog.Uri} uri The request destination. diff --git a/contexts/data/lib/closure-library/closure/goog/net/channelrequest.js b/contexts/data/lib/closure-library/closure/goog/net/channelrequest.js index 919962d..78701b8 100644 --- a/contexts/data/lib/closure-library/closure/goog/net/channelrequest.js +++ b/contexts/data/lib/closure-library/closure/goog/net/channelrequest.js @@ -28,6 +28,7 @@ goog.provide('goog.net.ChannelRequest'); goog.provide('goog.net.ChannelRequest.Error'); goog.require('goog.Timer'); +goog.require('goog.async.Throttle'); goog.require('goog.events'); goog.require('goog.events.EventHandler'); goog.require('goog.net.EventType'); @@ -50,8 +51,8 @@ goog.require('goog.userAgent'); * @param {number=} opt_retryId The retry id for this request. * @constructor */ -goog.net.ChannelRequest = function( - channel, channelDebug, opt_sessionId, opt_requestId, opt_retryId) { +goog.net.ChannelRequest = function(channel, channelDebug, opt_sessionId, + opt_requestId, opt_retryId) { /** * The BrowserChannel object that owns the request. * @type {goog.net.BrowserChannel|goog.net.BrowserTestChannel} @@ -255,6 +256,28 @@ goog.net.ChannelRequest.prototype.cancelled_ = false; /** + * A throttle time in ms for readystatechange events for the backchannel. + * Useful for throttling when ready state is INTERACTIVE (partial data). + * If set to zero no throttle is used. + * + * @see goog.net.BrowserChannel.prototype.readyStateChangeThrottleMs_ + * + * @type {number} + * @private + */ +goog.net.ChannelRequest.prototype.readyStateChangeThrottleMs_ = 0; + + +/** + * The throttle for readystatechange events for the current request, or null + * if there is none. + * @type {goog.async.Throttle} + * @private + */ +goog.net.ChannelRequest.prototype.readyStateChangeThrottle_ = null; + + +/** * Default timeout in MS for a request. The server must return data within this * time limit for the request to not timeout. * @type {number} @@ -335,7 +358,17 @@ goog.net.ChannelRequest.Error = { /** * Errors due to the handler throwing an exception. */ - HANDLER_EXCEPTION: 5 + HANDLER_EXCEPTION: 5, + + /** + * The browser declared itself offline during the request. + */ + BROWSER_OFFLINE: 6, + + /** + * IE is blocking ActiveX streaming. + */ + ACTIVE_X_BLOCKED: 7 }; @@ -387,7 +420,7 @@ goog.net.ChannelRequest.INCOMPLETE_CHUNK_ = {}; * @see http://code.google.com/p/closure-library/issues/detail?id=346 */ goog.net.ChannelRequest.supportsXhrStreaming = function() { - return !goog.userAgent.IE; + return !goog.userAgent.IE || goog.userAgent.isDocumentMode(10); }; @@ -412,6 +445,18 @@ goog.net.ChannelRequest.prototype.setTimeout = function(timeout) { /** + * Sets the throttle for handling onreadystatechange events for the request. + * + * @param {number} throttle The throttle in ms. A value of zero indicates + * no throttle. + */ +goog.net.ChannelRequest.prototype.setReadyStateChangeThrottle = function( + throttle) { + this.readyStateChangeThrottleMs_ = throttle; +}; + + +/** * Uses XMLHTTP to send an HTTP POST to the server. * * @param {goog.Uri} uri The uri of the request. @@ -476,8 +521,16 @@ goog.net.ChannelRequest.prototype.sendXmlHttp_ = function(hostPrefix) { var useSecondaryDomains = this.channel_.shouldUseSecondaryDomains(); this.xmlHttp_ = this.channel_.createXhrIo(useSecondaryDomains ? hostPrefix : null); - goog.events.listen(this.xmlHttp_, goog.net.EventType.READY_STATE_CHANGE, - this.xmlHttpHandler_, false, this); + + if (this.readyStateChangeThrottleMs_ > 0) { + this.readyStateChangeThrottle_ = new goog.async.Throttle( + goog.bind(this.xmlHttpHandler_, this, this.xmlHttp_), + this.readyStateChangeThrottleMs_); + } + + this.eventHandler_.listen(this.xmlHttp_, + goog.net.EventType.READY_STATE_CHANGE, + this.readyStateChangeHandler_); var headers = this.extraHeaders_ ? goog.object.clone(this.extraHeaders_) : {}; if (this.postData_) { @@ -497,6 +550,8 @@ goog.net.ChannelRequest.prototype.sendXmlHttp_ = function(hostPrefix) { } this.xmlHttp_.send(this.requestUri_, this.verb_, null, headers); } + this.channel_.notifyServerReachabilityEvent( + goog.net.BrowserChannel.ServerReachability.REQUEST_MADE); this.channelDebug_.xmlHttpChannelRequest(this.verb_, this.requestUri_, this.rid_, this.retryId_, this.postData_); @@ -504,12 +559,31 @@ goog.net.ChannelRequest.prototype.sendXmlHttp_ = function(hostPrefix) { /** + * Handles a readystatechange event. + * @param {goog.events.Event} evt The event. + * @private + */ +goog.net.ChannelRequest.prototype.readyStateChangeHandler_ = function(evt) { + var xhr = /** @type {goog.net.XhrIo} */ (evt.target); + var throttle = this.readyStateChangeThrottle_; + if (throttle && + xhr.getReadyState() == goog.net.XmlHttp.ReadyState.INTERACTIVE) { + // Only throttle in the partial data case. + this.channelDebug_.debug('Throttling readystatechange.'); + throttle.fire(); + } else { + // If we haven't throttled, just handle response directly. + this.xmlHttpHandler_(xhr); + } +}; + + +/** * XmlHttp handler - * @param {goog.events.Event} e Event object, target is a XhrIo object. + * @param {goog.net.XhrIo} xmlhttp The XhrIo object for the current request. * @private */ -goog.net.ChannelRequest.prototype.xmlHttpHandler_ = function(e) { - var xmlhttp = e.target; +goog.net.ChannelRequest.prototype.xmlHttpHandler_ = function(xmlhttp) { goog.net.BrowserChannel.onStartExecution(); /** @preserveTry */ try { @@ -540,6 +614,8 @@ goog.net.ChannelRequest.prototype.xmlHttpHandler_ = function(e) { */ goog.net.ChannelRequest.prototype.onXmlHttpReadyStateChanged_ = function() { var readyState = this.xmlHttp_.getReadyState(); + var errorCode = this.xmlHttp_.getLastErrorCode(); + var statusCode = this.xmlHttp_.getStatus(); // If it is Safari less than 420+, there is a bug that causes null to be // in the responseText on ready state interactive so we must wait for // ready state complete. @@ -564,6 +640,22 @@ goog.net.ChannelRequest.prototype.onXmlHttpReadyStateChanged_ = function() { } } + // Dispatch any appropriate network events. + if (!this.cancelled_ && readyState == goog.net.XmlHttp.ReadyState.COMPLETE && + errorCode != goog.net.ErrorCode.ABORT) { + + // Pretty conservative, these are the only known scenarios which we'd + // consider indicative of a truly non-functional network connection. + if (errorCode == goog.net.ErrorCode.TIMEOUT || + statusCode <= 0) { + this.channel_.notifyServerReachabilityEvent( + goog.net.BrowserChannel.ServerReachability.REQUEST_FAILED); + } else { + this.channel_.notifyServerReachabilityEvent( + goog.net.BrowserChannel.ServerReachability.REQUEST_SUCCEEDED); + } + } + // got some data so cancel the watchdog timer this.cancelWatchDogTimer_(); @@ -713,7 +805,8 @@ goog.net.ChannelRequest.prototype.pollResponse_ = function() { /** * Starts a polling interval for changes to responseText of the * XMLHttpRequest, for browsers that don't fire onreadystatechange - * as data comes in incrementally. + * as data comes in incrementally. This timer is disabled in + * cleanup_(). * @private */ goog.net.ChannelRequest.prototype.startPolling_ = function() { @@ -724,12 +817,27 @@ goog.net.ChannelRequest.prototype.startPolling_ = function() { /** - * Stops the polling interval for changes to responseText. + * Called when the browser declares itself offline at the start of a request or + * during its lifetime. Abandons that request. * @private */ -goog.net.ChannelRequest.prototype.stopPolling_ = function() { - this.pollingTimer_.stop(); - this.eventHandler_.removeAll(); +goog.net.ChannelRequest.prototype.cancelRequestAsBrowserIsOffline_ = + function() { + if (this.successful_) { + // Should never happen. + this.channelDebug_.severe( + 'Received browser offline event even though request completed ' + + 'successfully'); + } + + this.channelDebug_.browserOfflineResponse(this.requestUri_); + this.cleanup_(); + + // set error and dispatch failure + this.lastError_ = goog.net.ChannelRequest.Error.BROWSER_OFFLINE; + goog.net.BrowserChannel.notifyStatEvent( + goog.net.BrowserChannel.Stat.BROWSER_OFFLINE); + this.dispatchFailure_(); }; @@ -796,12 +904,26 @@ goog.net.ChannelRequest.prototype.tridentGet_ = function(usingSecondaryDomain) { this.requestStartTime_ = goog.now(); this.ensureWatchDogTimer_(); - this.trident_ = new ActiveXObject('htmlfile'); + var hostname = usingSecondaryDomain ? window.location.hostname : ''; + this.requestUri_ = this.baseUri_.clone(); + this.requestUri_.setParameterValue('DOMAIN', hostname); + this.requestUri_.setParameterValue('t', this.retryId_); + + try { + this.trident_ = new ActiveXObject('htmlfile'); + } catch (e) { + this.channelDebug_.severe('ActiveX blocked'); + this.cleanup_(); + + this.lastError_ = goog.net.ChannelRequest.Error.ACTIVE_X_BLOCKED; + goog.net.BrowserChannel.notifyStatEvent( + goog.net.BrowserChannel.Stat.ACTIVE_X_BLOCKED); + this.dispatchFailure_(); + return; + } - var hostname = ''; var body = '<html><body>'; if (usingSecondaryDomain) { - hostname = window.location.hostname; body += '<script>document.domain="' + hostname + '"</scr' + 'ipt>'; } body += '</body></html>'; @@ -817,12 +939,11 @@ goog.net.ChannelRequest.prototype.tridentGet_ = function(usingSecondaryDomain) { var div = this.trident_.createElement('div'); this.trident_.parentWindow.document.body.appendChild(div); - this.requestUri_ = this.baseUri_.clone(); - this.requestUri_.setParameterValue('DOMAIN', hostname); - this.requestUri_.setParameterValue('t', this.retryId_); div.innerHTML = '<iframe src="' + this.requestUri_ + '"></iframe>'; this.channelDebug_.tridentChannelRequest('GET', this.requestUri_, this.rid_, this.retryId_); + this.channel_.notifyServerReachabilityEvent( + goog.net.BrowserChannel.ServerReachability.REQUEST_MADE); }; @@ -885,10 +1006,11 @@ goog.net.ChannelRequest.prototype.onTridentDoneAsync_ = function(successful) { } this.channelDebug_.tridentChannelResponseDone( this.rid_, successful); - this.cancelWatchDogTimer_(); this.cleanup_(); this.successful_ = successful; this.channel_.onRequestComplete(this); + this.channel_.notifyServerReachabilityEvent( + goog.net.BrowserChannel.ServerReachability.BACK_CHANNEL_ACTIVITY); }; @@ -923,7 +1045,6 @@ goog.net.ChannelRequest.prototype.imgTagGet_ = function() { */ goog.net.ChannelRequest.prototype.cancel = function() { this.cancelled_ = true; - this.cancelWatchDogTimer_(); this.cleanup_(); }; @@ -1003,6 +1124,12 @@ goog.net.ChannelRequest.prototype.handleTimeout_ = function() { } this.channelDebug_.timeoutResponse(this.requestUri_); + // IMG requests never notice if they were successful, and always 'time out'. + // This fact says nothing about reachability. + if (this.type_ != goog.net.ChannelRequest.Type_.IMG) { + this.channel_.notifyServerReachabilityEvent( + goog.net.BrowserChannel.ServerReachability.REQUEST_FAILED); + } this.cleanup_(); // set error and dispatch failure @@ -1033,15 +1160,24 @@ goog.net.ChannelRequest.prototype.dispatchFailure_ = function() { * @private */ goog.net.ChannelRequest.prototype.cleanup_ = function() { - this.stopPolling_(); + this.cancelWatchDogTimer_(); + + goog.dispose(this.readyStateChangeThrottle_); + this.readyStateChangeThrottle_ = null; + + // Stop the polling timer, if necessary. + this.pollingTimer_.stop(); + + // Unhook all event handlers. + this.eventHandler_.removeAll(); + if (this.xmlHttp_) { // clear out this.xmlHttp_ before aborting so we handle getting reentered // inside abort var xmlhttp = this.xmlHttp_; this.xmlHttp_ = null; - goog.events.unlisten(xmlhttp, goog.net.EventType.READY_STATE_CHANGE, - this.xmlHttpHandler_, false, this); xmlhttp.abort(); + xmlhttp.dispose(); } if (this.trident_) { @@ -1131,6 +1267,8 @@ goog.net.ChannelRequest.prototype.safeOnRequestData_ = function(data) { /** @preserveTry */ try { this.channel_.onRequestData(this, data); + this.channel_.notifyServerReachabilityEvent( + goog.net.BrowserChannel.ServerReachability.BACK_CHANNEL_ACTIVITY); } catch (e) { // Dump debug info, but keep going without closing the channel. this.channelDebug_.dumpException( diff --git a/contexts/data/lib/closure-library/closure/goog/net/channelrequest_test.html b/contexts/data/lib/closure-library/closure/goog/net/channelrequest_test.html index 1bca491..4581067 100644 --- a/contexts/data/lib/closure-library/closure/goog/net/channelrequest_test.html +++ b/contexts/data/lib/closure-library/closure/goog/net/channelrequest_test.html @@ -11,21 +11,27 @@ See the COPYING file for details. <head> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>Closure Unit Tests - goog.net.ChannelRequest</title> -<script src="../base.js"></script> -<script> +<script src="../base.js" type="text/javascript"></script> +<script type="text/javascript"> goog.require('goog.functions'); goog.require('goog.net.BrowserChannel'); goog.require('goog.net.ChannelDebug'); goog.require('goog.net.ChannelRequest'); goog.require('goog.testing.MockClock'); +goog.require('goog.testing.PropertyReplacer'); goog.require('goog.testing.jsunit'); goog.require('goog.testing.net.XhrIo'); +goog.require('goog.testing.recordFunction'); </script> </head> <body> -<script> +<script type="text/javascript"> +var channelRequest; +var mockBrowserChannel; var mockClock; +var stubs; +var xhrIo; /** * Time to wait for a network request to time out, before aborting. @@ -33,6 +39,11 @@ var mockClock; var WATCHDOG_TIME = 2000; /** + * Time to throttle readystatechange events. + */ +var THROTTLE_TIME = 500; + +/** * A really long time - used to make sure no more timeouts will fire. */ var ALL_DAY_MS = 1000 * 60 * 60 * 24; @@ -41,10 +52,12 @@ var ALL_DAY_MS = 1000 * 60 * 60 * 24; function setUp() { mockClock = new goog.testing.MockClock(); mockClock.install(); + stubs = new goog.testing.PropertyReplacer(); } function tearDown() { + stubs.reset(); mockClock.uninstall(); } @@ -54,14 +67,7 @@ function tearDown() { * @constructor */ function MockBrowserChannel() { - this.createXhrIo = function(domainPrefix) { - assertNull(domainPrefix); - var xhrIo = new goog.testing.net.XhrIo(); - xhrIo.abort = xhrIo.abort || function() { - this.active_ = false; - }; - return xhrIo; - } + this.reachabilityEvents = {}; this.isClosed = function() { return false; }; @@ -72,6 +78,12 @@ function MockBrowserChannel() { return false; } this.completedRequests = []; + this.notifyServerReachabilityEvent = function(reachabilityType) { + if (!this.reachabilityEvents[reachabilityType]) { + this.reachabilityEvents[reachabilityType] = 0; + } + this.reachabilityEvents[reachabilityType]++; + }; this.onRequestComplete = function(request) { this.completedRequests.push(request); }; @@ -84,49 +96,102 @@ function MockBrowserChannel() { * testability: * <ul> * <li>The BrowserChannel is a MockBrowserChannel. - * <li>createXhrIo_() returns the xhrIo that is passed in. * <li>The new watchdogTimeoutCallCount property tracks onWatchDogTimeout_() * calls. * <li>The timeout is set to WATCHDOG_TIME. * </ul> - * @param {goog.testing.net.XhrIo} xhrIo A test XhrIo. - * @return {goog.net.ChannelRequest} A slightly modified ChannelRequest */ -function createChannelRequest(xhrIo) { +function createChannelRequest() { + xhrIo = new goog.testing.net.XhrIo(); + xhrIo.abort = xhrIo.abort || function() { + this.active_ = false; + }; + // Install mock browser channel and no-op debug logger. - var req = new goog.net.ChannelRequest( - new MockBrowserChannel(), + mockBrowserChannel = new MockBrowserChannel(); + channelRequest = new goog.net.ChannelRequest( + mockBrowserChannel, new goog.net.ChannelDebug()); // Install test XhrIo. - req.createXhrIo_ = function() { + mockBrowserChannel.createXhrIo = function() { return xhrIo; }; // Install watchdogTimeoutCallCount. - req.watchdogTimeoutCallCount = 0; - req.originalOnWatchDogTimeout = req.onWatchDogTimeout_; - req.onWatchDogTimeout_ = function() { + channelRequest.watchdogTimeoutCallCount = 0; + channelRequest.originalOnWatchDogTimeout = channelRequest.onWatchDogTimeout_; + channelRequest.onWatchDogTimeout_ = function() { this.watchdogTimeoutCallCount++; return this.originalOnWatchDogTimeout(); }; - req.setTimeout(WATCHDOG_TIME); + channelRequest.setTimeout(WATCHDOG_TIME); +} + - return req; +/** + * Run through the lifecycle of a long lived request, checking that the right + * network events are reported. + */ +function testNetworkEvents() { + createChannelRequest(); + + channelRequest.xmlHttpPost(new goog.Uri('some_uri'), 'some_postdata', true); + checkReachabilityEvents(1, 0, 0, 0); + if (goog.net.ChannelRequest.supportsXhrStreaming()) { + xhrIo.simulatePartialResponse('17\nI am a BC Message'); + checkReachabilityEvents(1, 0, 0, 1); + xhrIo.simulatePartialResponse('23\nI am another BC Message'); + checkReachabilityEvents(1, 0, 0, 2); + xhrIo.simulateResponse(200, '16\Final BC Message'); + checkReachabilityEvents(1, 1, 0, 2); + } else { + xhrIo.simulateResponse(200, '16\Final BC Message'); + checkReachabilityEvents(1, 1, 0, 0); + } } /** - * Creates a test XhrIo, with the abort() method defined. - * @return {goog.testing.net.XhrIo} A test XhrIo. + * Test throttling of readystatechange events. */ -function createXhrIo() { - var xhrIo = new goog.testing.net.XhrIo(); - xhrIo.abort = xhrIo.abort || function() { - this.active_ = false; - }; - return xhrIo; +function testNetworkEvents_throttleReadyStateChange() { + createChannelRequest(); + channelRequest.setReadyStateChangeThrottle(THROTTLE_TIME); + + var recordedHandler = + goog.testing.recordFunction(channelRequest.xmlHttpHandler_); + stubs.set(channelRequest, 'xmlHttpHandler_', recordedHandler); + + channelRequest.xmlHttpPost(new goog.Uri('some_uri'), 'some_postdata', true); + assertEquals(1, recordedHandler.getCallCount()); + + checkReachabilityEvents(1, 0, 0, 0); + if (goog.net.ChannelRequest.supportsXhrStreaming()) { + xhrIo.simulatePartialResponse('17\nI am a BC Message'); + checkReachabilityEvents(1, 0, 0, 1); + assertEquals(3, recordedHandler.getCallCount()); + + // Second event should be throttled + xhrIo.simulatePartialResponse('23\nI am another BC Message'); + assertEquals(3, recordedHandler.getCallCount()); + + xhrIo.simulatePartialResponse('27\nI am yet another BC Message'); + assertEquals(3, recordedHandler.getCallCount()); + mockClock.tick(THROTTLE_TIME); + + checkReachabilityEvents(1, 0, 0, 3); + // Only one more call because of throttling. + assertEquals(4, recordedHandler.getCallCount()); + + xhrIo.simulateResponse(200, '16\Final BC Message'); + checkReachabilityEvents(1, 1, 0, 3); + assertEquals(5, recordedHandler.getCallCount()); + } else { + xhrIo.simulateResponse(200, '16\Final BC Message'); + checkReachabilityEvents(1, 1, 0, 0); + } } @@ -135,53 +200,81 @@ function createXhrIo() { * expires. */ function testRequestTimeout() { - var xhrIo = createXhrIo(); - var req = createChannelRequest(xhrIo); + createChannelRequest(); - req.xmlHttpPost(new goog.Uri('some_uri'), 'some_postdata', true); - assertEquals(0, req.watchdogTimeoutCallCount); - assertEquals(0, req.channel_.completedRequests.length); + channelRequest.xmlHttpPost(new goog.Uri('some_uri'), 'some_postdata', true); + assertEquals(0, channelRequest.watchdogTimeoutCallCount); + assertEquals(0, channelRequest.channel_.completedRequests.length); // Watchdog timeout. mockClock.tick(WATCHDOG_TIME); - assertEquals(1, req.watchdogTimeoutCallCount); - assertEquals(1, req.channel_.completedRequests.length); - assertFalse(req.getSuccess()); + assertEquals(1, channelRequest.watchdogTimeoutCallCount); + assertEquals(1, channelRequest.channel_.completedRequests.length); + assertFalse(channelRequest.getSuccess()); // Make sure no more timers are firing. mockClock.tick(ALL_DAY_MS); - assertEquals(1, req.watchdogTimeoutCallCount); - assertEquals(1, req.channel_.completedRequests.length); + assertEquals(1, channelRequest.watchdogTimeoutCallCount); + assertEquals(1, channelRequest.channel_.completedRequests.length); + + checkReachabilityEvents(1, 0, 1, 0); } + function testRequestTimeoutWithUnexpectedException() { - var xhrIo = createXhrIo(); - var req = createChannelRequest(xhrIo); - req.channel_.createXhrIo = goog.functions.error('Weird error'); + createChannelRequest(); + channelRequest.channel_.createXhrIo = goog.functions.error('Weird error'); try { - req.xmlHttpGet(new goog.Uri('some_uri'), true, null); + channelRequest.xmlHttpGet(new goog.Uri('some_uri'), true, null); fail('Expected error'); } catch (e) { assertEquals('Weird error', e.message); } - assertEquals(0, req.watchdogTimeoutCallCount); - assertEquals(0, req.channel_.completedRequests.length); + assertEquals(0, channelRequest.watchdogTimeoutCallCount); + assertEquals(0, channelRequest.channel_.completedRequests.length); // Watchdog timeout. mockClock.tick(WATCHDOG_TIME); - assertEquals(1, req.watchdogTimeoutCallCount); - assertEquals(1, req.channel_.completedRequests.length); - assertFalse(req.getSuccess()); + assertEquals(1, channelRequest.watchdogTimeoutCallCount); + assertEquals(1, channelRequest.channel_.completedRequests.length); + assertFalse(channelRequest.getSuccess()); // Make sure no more timers are firing. mockClock.tick(ALL_DAY_MS); - assertEquals(1, req.watchdogTimeoutCallCount); - assertEquals(1, req.channel_.completedRequests.length); + assertEquals(1, channelRequest.watchdogTimeoutCallCount); + assertEquals(1, channelRequest.channel_.completedRequests.length); + + checkReachabilityEvents(0, 0, 1, 0); +} + +function testActiveXBlocked() { + createChannelRequest(); + stubs.set(goog.global, 'ActiveXObject', + goog.functions.error('Active X blocked')); + + channelRequest.tridentGet(new goog.Uri('some_uri'), false); + assertFalse(channelRequest.getSuccess()); + assertEquals(goog.net.ChannelRequest.Error.ACTIVE_X_BLOCKED, + channelRequest.getLastError()); + + checkReachabilityEvents(0, 0, 0, 0); } +function checkReachabilityEvents(reqMade, reqSucceeded, reqFail, backChannel) { + var Reachability = goog.net.BrowserChannel.ServerReachability; + assertEquals(reqMade, + mockBrowserChannel.reachabilityEvents[Reachability.REQUEST_MADE] || 0); + assertEquals(reqSucceeded, + mockBrowserChannel.reachabilityEvents[Reachability.REQUEST_SUCCEEDED] || 0); + assertEquals(reqFail, + mockBrowserChannel.reachabilityEvents[Reachability.REQUEST_FAILED] || 0); + assertEquals(backChannel, + mockBrowserChannel.reachabilityEvents[Reachability.BACK_CHANNEL_ACTIVITY] + || 0); +} </script> </body> </html> diff --git a/contexts/data/lib/closure-library/closure/goog/net/cookies.js b/contexts/data/lib/closure-library/closure/goog/net/cookies.js index 9978f27..10cc5b8 100644 --- a/contexts/data/lib/closure-library/closure/goog/net/cookies.js +++ b/contexts/data/lib/closure-library/closure/goog/net/cookies.js @@ -60,35 +60,11 @@ goog.net.Cookies.SPLIT_RE_ = /\s*;\s*/; /** - * Test cookie name. Used for a temp cookie when testing if cookies are - * enabled. - * @type {string} - * @private - */ -goog.net.Cookies.TEST_COOKIE_NAME_ = 'COOKIES_TEST_'; - - -/** * Returns true if cookies are enabled. * @return {boolean} True if cookies are enabled. */ goog.net.Cookies.prototype.isEnabled = function() { - var isEnabled = this.isNavigatorCookieEnabled_(); - - if (isEnabled && goog.userAgent.WEBKIT) { - // Chrome has a bug where it will report cookies as enabled even if they - // are not, see http://code.google.com/p/chromium/issues/detail?id=1850 . - // To work around, we set a unique cookie, then check for it. - var cookieName = goog.net.Cookies.TEST_COOKIE_NAME_ + goog.now(); - goog.net.cookies.set(cookieName, '1'); - if (!this.get(cookieName)) { - return false; - } - // Remove temp cookie. - this.remove(cookieName); - } - - return isEnabled; + return navigator.cookieEnabled; }; @@ -217,6 +193,9 @@ goog.net.Cookies.prototype.get = function(name, opt_default) { if (part.indexOf(nameEq) == 0) { return part.substr(nameEq.length); } + if (part == name) { + return ''; + } } return opt_default; }; @@ -354,16 +333,6 @@ goog.net.Cookies.prototype.getParts_ = function() { /** - * Returns navigator.cookieEnabled. Overridden in unit tests. - * @return {boolean} The value of navigator.cookieEnabled. - * @private - */ -goog.net.Cookies.prototype.isNavigatorCookieEnabled_ = function() { - return navigator.cookieEnabled; -}; - - -/** * Gets the names and values for all the cookies. * @return {Object} An object with keys and values. * @private diff --git a/contexts/data/lib/closure-library/closure/goog/net/cookies_test.html b/contexts/data/lib/closure-library/closure/goog/net/cookies_test.html index 10ec66c..170e686 100644 --- a/contexts/data/lib/closure-library/closure/goog/net/cookies_test.html +++ b/contexts/data/lib/closure-library/closure/goog/net/cookies_test.html @@ -13,6 +13,7 @@ See the COPYING file for details. <script> goog.require('goog.array'); goog.require('goog.net.cookies'); + goog.require('goog.testing.PropertyReplacer'); goog.require('goog.testing.jsunit'); </script> </head> @@ -21,6 +22,7 @@ See the COPYING file for details. var cookies = goog.net.cookies; var baseCount = 0; +var stubs = new goog.testing.PropertyReplacer(); function checkForCookies() { if (!cookies.isEnabled()) { @@ -46,20 +48,11 @@ function setUp() { function tearDown() { // Clear up after ourselves. cookies.clear(); + stubs.reset(); } function testIsEnabled() { - // Save static function prior to mocking. - var isNavigatorCookieEnabled = cookies.isNavigatorCookieEnabled_; - try { - cookies.isNavigatorCookieEnabled_ = function() { return true; }; - assertTrue(cookies.isEnabled()); - cookies.isNavigatorCookieEnabled_ = function() { return false; }; - assertFalse(cookies.isEnabled()); - } finally { - // Restore static function. - cookies.isNavigatorCookieEnabled_ = isNavigatorCookieEnabled; - } + assertEquals(navigator.cookieEnabled, cookies.isEnabled()); } function testCount() { @@ -196,6 +189,24 @@ function testSetCookieMaxAgeZero() { } } +function testGetEmptyCookie() { + var value = ''; + + cookies.set('test', value); + + assertEquals(value, cookies.get('test')); +} + +function testGetEmptyCookieIE() { + stubs.set(cookies, 'getCookie_', function() { + return 'test1; test2; test3'; + }); + + assertEquals('', cookies.get('test1')); + assertEquals('', cookies.get('test2')); + assertEquals('', cookies.get('test3')); +} + // TODO(chrisn): Testing max age > 0 requires a mock clock. function mockSetCookie(var_args) { diff --git a/contexts/data/lib/closure-library/closure/goog/net/crossdomainrpc_test.css b/contexts/data/lib/closure-library/closure/goog/net/crossdomainrpc_test.css new file mode 100644 index 0000000..73cc311 --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/net/crossdomainrpc_test.css @@ -0,0 +1,7 @@ +/* + * Copyright 2010 The Closure Library Authors. All Rights Reserved. + * + * Use of this source code is governed by the Apache License, Version 2.0. + * See the COPYING file for details. + */ + diff --git a/contexts/data/lib/closure-library/closure/goog/net/httpstatus.js b/contexts/data/lib/closure-library/closure/goog/net/httpstatus.js index eecb270..8b6ef75 100755 --- a/contexts/data/lib/closure-library/closure/goog/net/httpstatus.js +++ b/contexts/data/lib/closure-library/closure/goog/net/httpstatus.js @@ -88,7 +88,8 @@ goog.net.HttpStatus = { * Returns whether the given status should be considered successful. * * Successful codes are OK (200), CREATED (201), ACCEPTED (202), - * NO CONTENT (204), NOT MODIFIED (304), and IE's no content code (1223). + * NO CONTENT (204), PARTIAL CONTENT (206), NOT MODIFIED (304), + * and IE's no content code (1223). * * @param {number} status The status code to test. * @return {boolean} Whether the status code should be considered successful. @@ -99,6 +100,7 @@ goog.net.HttpStatus.isSuccess = function(status) { case goog.net.HttpStatus.CREATED: case goog.net.HttpStatus.ACCEPTED: case goog.net.HttpStatus.NO_CONTENT: + case goog.net.HttpStatus.PARTIAL_CONTENT: case goog.net.HttpStatus.NOT_MODIFIED: case goog.net.HttpStatus.QUIRK_IE_NO_CONTENT: return true; diff --git a/contexts/data/lib/closure-library/closure/goog/net/imageloader.js b/contexts/data/lib/closure-library/closure/goog/net/imageloader.js index cbe4467..5cd2a5f 100644 --- a/contexts/data/lib/closure-library/closure/goog/net/imageloader.js +++ b/contexts/data/lib/closure-library/closure/goog/net/imageloader.js @@ -18,10 +18,12 @@ * * @author attila@google.com (Attila Bodis) * @author zachlloyd@google.com (Zachary Lloyd) + * @author jonemerson@google.com (Jon Emerson) */ goog.provide('goog.net.ImageLoader'); +goog.require('goog.array'); goog.require('goog.dom'); goog.require('goog.events.EventHandler'); goog.require('goog.events.EventTarget'); @@ -37,6 +39,23 @@ goog.require('goog.userAgent'); * event for each image loaded, with an {@link Image} object as the target of * the event, normalized to have {@code naturalHeight} and {@code naturalWidth} * attributes. + * + * To use this class, run: + * + * <pre> + * var imageLoader = new goog.net.ImageLoader(); + * goog.events.listen(imageLoader, goog.net.EventType.COMPLETE, + * function(e) { ... }); + * imageLoader.addImage("image_id", "http://path/to/image.gif"); + * imageLoader.start(); + * </pre> + * + * The start() method must be called to start image loading. Images can be + * added and removed after loading has started, but only those images added + * before start() was called will be loaded until start() is called again. + * A goog.net.EventType.COMPLETE event will be dispatched only once all + * outstanding images have completed uploading. + * * @param {Element=} opt_parent An optional parent element whose document object * should be used to load images. * @constructor @@ -44,38 +63,61 @@ goog.require('goog.userAgent'); */ goog.net.ImageLoader = function(opt_parent) { goog.events.EventTarget.call(this); - this.images_ = {}; + + /** + * Map of image IDs to their image src, used to keep track of the images to + * load. Once images have started loading, they're removed from this map. + * @type {!Object.<string, string>} + * @private + */ + this.imageIdToUrlMap_ = {}; + + /** + * Map of image IDs to their image element, used only for images that are in + * the process of loading. Used to clean-up event listeners and to know + * when we've completed loading images. + * @type {!Object.<string, !Element>} + * @private + */ + this.imageIdToImageMap_ = {}; + + /** + * Event handler object, used to keep track of onload and onreadystatechange + * listeners. + * @type {!goog.events.EventHandler} + * @private + */ this.handler_ = new goog.events.EventHandler(this); + + /** + * The parent element whose document object will be used to load images. + * Useful if you want to load the images from a window other than the current + * window in order to control the Referer header sent when the image is + * loaded. + * @type {Element|undefined} + * @private + */ this.parent_ = opt_parent; }; goog.inherits(goog.net.ImageLoader, goog.events.EventTarget); /** - * Map of image IDs to images src, used to keep track of the images to load. - * @private - * @type {Object.<string, string>} - */ -goog.net.ImageLoader.prototype.images_; - - -/** - * Event handler object, used to keep track of onload and onreadystatechange - * listeners. + * An array of event types to listen to on images. This is browser dependent. + * Internet Explorer doesn't reliably raise LOAD events on images, so we must + * use READY_STATE_CHANGE. If the image is cached locally, IE won't fire the + * LOAD event while the onreadystate event is fired always. On the other hand, + * the ERROR event is always fired whenever the image is not loaded successfully + * no matter whether it's cached or not. + * @type {!Array.<string>} * @private - * @type {goog.events.EventHandler} */ -goog.net.ImageLoader.prototype.handler_; - - -/** - * The parent element whose document object will be used to load images. - * Useful if you want to load the images from a window other than the current - * window in order to control the Referer header sent when the image is loaded. - * @type {(Element|undefined)} - * @private - */ -goog.net.ImageLoader.prototype.parent_; +goog.net.ImageLoader.IMAGE_LOAD_EVENTS_ = [ + goog.userAgent.IE ? goog.net.EventType.READY_STATE_CHANGE : + goog.events.EventType.LOAD, + goog.net.EventType.ABORT, + goog.net.EventType.ERROR +]; /** @@ -92,17 +134,34 @@ goog.net.ImageLoader.prototype.addImage = function(id, image) { var src = goog.isString(image) ? image : image.src; if (src) { // For now, we just store the source URL for the image. - this.images_[id] = src; + this.imageIdToUrlMap_[id] = src; } }; /** * Removes the image associated with the given ID string from the image loader. + * If the image was previously loading, removes any listeners for its events + * and dispatches a COMPLETE event if all remaining images have now completed. * @param {string} id The ID of the image to remove. */ goog.net.ImageLoader.prototype.removeImage = function(id) { - goog.object.remove(this.images_, id); + delete this.imageIdToUrlMap_[id]; + + var image = this.imageIdToImageMap_[id]; + if (image) { + delete this.imageIdToImageMap_[id]; + + // Stop listening for events on the image. + this.handler_.unlisten(image, goog.net.ImageLoader.IMAGE_LOAD_EVENTS_, + this.onNetworkEvent_); + + // If this was the last image, raise a COMPLETE event. + if (goog.object.isEmpty(this.imageIdToImageMap_) && + goog.object.isEmpty(this.imageIdToUrlMap_)) { + this.dispatchEvent(goog.net.EventType.COMPLETE); + } + } }; @@ -112,18 +171,36 @@ goog.net.ImageLoader.prototype.removeImage = function(id) { * images have finished loading. */ goog.net.ImageLoader.prototype.start = function() { - goog.object.forEach(this.images_, this.loadImage_, this); + // Iterate over the keys, rather than the full object, to essentially clone + // the initial queued images in case any event handlers decide to add more + // images before this loop has finished executing. + var imageIdToUrlMap = this.imageIdToUrlMap_; + goog.array.forEach(goog.object.getKeys(imageIdToUrlMap), + function(id) { + var src = imageIdToUrlMap[id]; + if (src) { + delete imageIdToUrlMap[id]; + this.loadImage_(src, id); + } + }, this); }; /** * Creates an {@code Image} object with the specified ID and source URL, and * listens for network events raised as the image is loaded. - * @private * @param {string} src The image source URL. * @param {string} id The unique ID of the image to load. + * @private */ goog.net.ImageLoader.prototype.loadImage_ = function(src, id) { + if (this.isDisposed()) { + // When loading an image in IE7 (and maybe IE8), the error handler + // may fire before we yield JS control. If the error handler + // dispose the ImageLoader, this method will throw exception. + return; + } + var image; if (this.parent_) { var dom = goog.dom.getDomHelper(this.parent_); @@ -132,18 +209,9 @@ goog.net.ImageLoader.prototype.loadImage_ = function(src, id) { image = new Image(); } - // Internet Explorer doesn't reliably raise LOAD events on images, so we must - // use READY_STATE_CHANGE (thanks, Jeff!). - // If the image is cached locally, IE won't fire the LOAD event while the - // onreadystate event is fired always. On the other hand, the ERROR event - // is always fired whenever the image is not loaded successfully no matter - // whether it's cached or not. - - var loadEvent = goog.userAgent.IE ? goog.net.EventType.READY_STATE_CHANGE : - goog.events.EventType.LOAD; - this.handler_.listen(image, [ - loadEvent, goog.net.EventType.ABORT, goog.net.EventType.ERROR - ], this.onNetworkEvent_); + this.handler_.listen(image, goog.net.ImageLoader.IMAGE_LOAD_EVENTS_, + this.onNetworkEvent_); + this.imageIdToImageMap_[id] = image; image.id = id; image.src = src; @@ -152,18 +220,18 @@ goog.net.ImageLoader.prototype.loadImage_ = function(src, id) { /** * Handles net events (READY_STATE_CHANGE, LOAD, ABORT, and ERROR). - * @private * @param {goog.events.Event} evt The network event to handle. + * @private */ goog.net.ImageLoader.prototype.onNetworkEvent_ = function(evt) { - var image = evt.currentTarget; + var image = /** @type {Element} */ (evt.currentTarget); if (!image) { return; } if (evt.type == goog.net.EventType.READY_STATE_CHANGE) { - // This implies that the user agent is IE; see loadImage()_. + // This implies that the user agent is IE; see loadImage_(). // Noe that this block is used to check whether the image is ready to // dispatch the COMPLETE event. if (image.readyState == goog.net.EventType.COMPLETE) { @@ -210,28 +278,15 @@ goog.net.ImageLoader.prototype.onNetworkEvent_ = function(evt) { return; } - // Remove the image from the map. - goog.object.remove(this.images_, image.id); - - // If this was the last image, raise a COMPLETE event. - if (goog.object.isEmpty(this.images_)) { - this.dispatchEvent(goog.net.EventType.COMPLETE); - // Unlisten for all network events. - if (this.handler_) { - this.handler_.removeAll(); - } - } + this.removeImage(image.id); }; /** @override */ goog.net.ImageLoader.prototype.disposeInternal = function() { - if (this.images_) { - delete this.images_; - } - if (this.handler_) { - this.handler_.dispose(); - this.handler_ = null; - } + delete this.imageIdToUrlMap_; + delete this.imageIdToImageMap_; + goog.dispose(this.handler_); + goog.net.ImageLoader.superClass_.disposeInternal.call(this); }; diff --git a/contexts/data/lib/closure-library/closure/goog/net/imageloader_test.html b/contexts/data/lib/closure-library/closure/goog/net/imageloader_test.html index 9d8b3d8..1e2f045 100644 --- a/contexts/data/lib/closure-library/closure/goog/net/imageloader_test.html +++ b/contexts/data/lib/closure-library/closure/goog/net/imageloader_test.html @@ -13,187 +13,289 @@ See the COPYING file for details. <title>Closure Unit Tests - goog.net.ImageLoader</title> <script src="../base.js"></script> <script> + goog.require('goog.Timer'); + goog.require('goog.dispose'); goog.require('goog.events'); goog.require('goog.events.EventType'); goog.require('goog.net.ImageLoader'); - goog.require('goog.structs.Map'); + goog.require('goog.object'); + goog.require('goog.testing.AsyncTestCase'); goog.require('goog.testing.jsunit'); + goog.require('goog.testing.recordFunction'); </script> </head> <body> <script> +var asyncTestCase = goog.testing.AsyncTestCase.createAndInstall(document.title); +// Set the AsyncTestCase timeout to larger value to allow more time +// for images to load. +asyncTestCase.stepTimeout = 5000; - var TEST_IMAGES = new goog.structs.Map(); +var TEST_EVENT_TYPES = [ + goog.events.EventType.LOAD, + goog.net.EventType.COMPLETE, + goog.net.EventType.ERROR +]; - var TEST_EVENT_TYPES = [ - goog.events.EventType.LOAD, - goog.net.EventType.COMPLETE, - goog.net.EventType.ERROR - ]; - // TEST_IMAGES.set(FileName, Expected Size (width, height), Expected event) - var EVENT_TYPE_LOAD = goog.events.EventType.LOAD; - TEST_IMAGES.set('imageloader_testimg1.gif', [20, 20, EVENT_TYPE_LOAD]); - TEST_IMAGES.set('imageloader_testimg2.gif', [20, 20, EVENT_TYPE_LOAD]); - TEST_IMAGES.set('imageloader_testimg3.gif', [32, 32, EVENT_TYPE_LOAD]); +/** + * Mapping from test image file name to: + * [expected width, expected height, expected event to be fired]. + */ +var TEST_IMAGES = { + 'imageloader_testimg1.gif': [20, 20, goog.events.EventType.LOAD], + 'imageloader_testimg2.gif': [20, 20, goog.events.EventType.LOAD], + 'imageloader_testimg3.gif': [32, 32, goog.events.EventType.LOAD], - var EVENT_TYPE_ERROR = goog.net.EventType.ERROR; - TEST_IMAGES.set('this-is-not-image-1.gif', [0, 0, EVENT_TYPE_ERROR]); - TEST_IMAGES.set('this-is-not-image-2.gif', [0, 0, EVENT_TYPE_ERROR]); + 'this-is-not-image-1.gif': [0, 0, goog.net.EventType.ERROR], + 'this-is-not-image-2.gif': [0, 0, goog.net.EventType.ERROR] +}; - var TIMEOUT = 5000; - // in milleseconds - // Create a new test case. - var imageLoaderTestCase = new goog.testing.TestCase(document.title); - var setUpPageStatus; +var startTime; +var loader; - // Keep track of time so we can timeout if the images don't load. - imageLoaderTestCase.elapsedTime_ = 0; - imageLoaderTestCase.results_ = new goog.structs.Map(); +function setUp() { + startTime = goog.now(); - /** True once the test environment is set up. */ - imageLoaderTestCase.isSetUp = false; - - /** True once the page is ready for the test to be run. */ - imageLoaderTestCase.isReady = false; - - // A regular image loader. - imageLoaderTestCase.imageLoader = new goog.net.ImageLoader(); - - // An image loader that is used to check whether we can dispose - // it safely whenever an event is fired before the COMPLETE event. - imageLoaderTestCase.disposalImageLoader = new goog.net.ImageLoader(); - - /** Sets up the test environment, adds tests and sets up the worker pools. */ - imageLoaderTestCase.setUpTests = function() { - this.log('Setting tests up'); - - this.add(new goog.testing.TestCase.Test('testCompleteResults', - this.testCompleteResults, this)); - - this.isSetUp = true; - - var keys = TEST_IMAGES.getKeys(); - for (var i = 0; i < keys.length; i++) { - this.log('Adding image: ' + keys[i]); - this.imageLoader.addImage('img_' + i, keys[i]); - this.disposalImageLoader.addImage('img_' + i, keys[i]); - } - - goog.events.listen(this.imageLoader, TEST_EVENT_TYPES, - this.handleImageLoaderEvent, false, this); - - goog.events.listen(this.disposalImageLoader, TEST_EVENT_TYPES, - this.handleDisposalImageLoaderEvent, false, this); - - this.disposalImageLoader.start(); - }; - - /** Handles any events fired on the disposalImageLoader */ - imageLoaderTestCase.handleDisposalImageLoaderEvent = function(e) { - switch (e.type) { - case goog.events.EventType.LOAD: - case goog.net.EventType.ERROR: - // Make sure that we can dispose this.disposalImageLoader safely. - this.disposalImageLoader.dispose(); - - // then starts the regular image loader. - this.imageLoader.start(); - break; - - case goog.net.EventType.COMPLETE: - throw new Error('disposalImageLoader should have been disposed.'); - break; - } - }; + loader = new goog.net.ImageLoader(); + // Adds test images to the loader. + var i = 0; + for (var key in TEST_IMAGES) { + var imageId = 'img_' + i++; + loader.addImage(imageId, key); + } +} - /** Handles any events fired on the imageLoader */ - imageLoaderTestCase.handleImageLoaderEvent = function(e) { - this.log('handleEvent, type: ' + e.type); - - switch (e.type) { - case goog.events.EventType.LOAD: - var image = e.target; - this.results_.set(image.src.substring(image.src.lastIndexOf('/') + 1), - [image.naturalWidth, image.naturalHeight, e.type]); - break; - - case goog.net.EventType.ERROR: - var image = e.target; - this.results_.set(image.src.substring(image.src.lastIndexOf('/') + 1), - [image.naturalWidth, image.naturalHeight, e.type]); - break; - - case goog.net.EventType.COMPLETE: - setUpPageStatus = 'complete'; - this.isReady = true; - break; - } - }; +function tearDown() { + goog.dispose(loader); +} - /** Tests the results. */ - imageLoaderTestCase.testCompleteResults = function() { - var keys = TEST_IMAGES.getKeys(); - for (var i = 0; i < keys.length; i++) { - var key = keys[i]; - this.log(key); - // Check if fires the COMPLETE event. - assertTrue('Image is not loaded completely', - this.results_.containsKey(key)); +/** + * Tests loading image and disposing before loading completes. + */ +function testDisposeInTheMiddleOfLoadingWorks() { + goog.events.listen(loader, TEST_EVENT_TYPES, + goog.partial(handleDisposalImageLoaderEvent, loader)); + // waitForAsync before starting loader just in case + // handleDisposalImageLoaderEvent is called from within loader.start + // (before we yield control). This may happen in IE7/IE8. + asyncTestCase.waitForAsync('Waiting for loader handler to fire.'); + loader.start(); +} - // Chcekc size. - assertTrue('Image size is not correct', - this.results_.get(key)[0] == TEST_IMAGES.get(key)[0] && - this.results_.get(key)[1] == TEST_IMAGES.get(key)[1]); - // Check if fired the correct event. - assertTrue('Event *' + TEST_IMAGES.get(key)[2] + '* must be fired', - this.results_.get(key)[2] == TEST_IMAGES.get(key)[2]); - } - }; +function handleDisposalImageLoaderEvent(loader, e) { + assertFalse('Handler is still invoked after loader is disposed.', + loader.isDisposed()); - /** Waits until the tests are ready to begin, before running them. */ - imageLoaderTestCase.runTests = function() { - if (!this.isSetUp) { - this.setUpTests(); - } - if (this.isReady) { - this.execute(); - } else { - if (this.elapsedTime_ > TIMEOUT) { - this.log('timed out'); - setUpPageStatus = 'complete'; - this.isReady = true; - return; - } - this.log('Not ready, waiting'); - this.elapsedTime_ += 100; - // Try again in 100ms - setTimeout('imageLoaderTestCase.runTests()', 100); - } - }; + switch (e.type) { + case goog.net.EventType.COMPLETE: + fail('This test should never get COMPLETE event.'); + return; - /** Used by the JsUnit test runner. */ - function testCompleteResults() { - imageLoaderTestCase.testCompleteResults(); + case goog.events.EventType.LOAD: + case goog.net.EventType.ERROR: + loader.dispose(); + break; } - /** Used by the JsUnit test runner. */ - function setUpPage() { - imageLoaderTestCase.runTests(); - } + // Make sure that handler is never called again after disposal before + // marking test as successful. + asyncTestCase.waitForAsync('Wait to ensure that COMPLETE is never fired'); + goog.Timer.callOnce(function() { + asyncTestCase.continueTesting(); + }, 500); +} + + +/** + * Tests loading of images until completion. + */ +function testLoadingUntilCompletion() { + var results = {}; + goog.events.listen(loader, TEST_EVENT_TYPES, + function(e) { + switch (e.type) { + case goog.events.EventType.LOAD: + var image = e.target; + results[image.src.substring(image.src.lastIndexOf('/') + 1)] = + [image.naturalWidth, image.naturalHeight, e.type]; + return; + + case goog.net.EventType.ERROR: + var image = e.target; + results[image.src.substring(image.src.lastIndexOf('/') + 1)] = + [image.naturalWidth, image.naturalHeight, e.type]; + return; + + case goog.net.EventType.COMPLETE: + // Test completes successfully. + asyncTestCase.continueTesting(); + + assertImagesAreCorrect(results); + return; + } + }); + + // waitForAsync before starting loader just in case handleImageLoaderEvent + // is called from within loader.start (before we yield control). + // This may happen in IE7/IE8. + asyncTestCase.waitForAsync('Waiting for loader handler to fire.'); + loader.start(); +} + + +function assertImagesAreCorrect(results) { + assertEquals( + goog.object.getCount(TEST_IMAGES), goog.object.getCount(results)); + goog.object.forEach(TEST_IMAGES, function(value, key) { + // Check if fires the COMPLETE event. + assertTrue('Image is not loaded completely.', key in results); + + var image = results[key]; + + // Check image size. + assertEquals('Image width is not correct', value[0], image[0]); + assertEquals('Image length is not correct', value[1], image[1]); + + // Check if fired the correct event. + assertEquals('Event *' + value[2] + '* must be fired', value[2], image[2]); + }); +} + + +/** + * Overrides the loader's loadImage_ method so that it dispatches an image + * loaded event immediately, causing any event listners to receive them + * synchronously. This allows tests to assume synchronous execution. + */ +function makeLoaderSynchronous(loader) { + var originalLoadImage = loader.loadImage_; + loader.loadImage_ = function(src, id) { + originalLoadImage.call(this, src, id); + + var event = new goog.events.Event(goog.events.EventType.LOAD); + event.currentTarget = this.imageIdToImageMap_[id]; + loader.onNetworkEvent_(event); + }; - /** Standalone Closure Test Runner. */ - if (typeof G_testRunner != 'undefined') { - G_testRunner.initialize(imageLoaderTestCase); - } + // Make listen() a no-op. + loader.handler_.listen = goog.nullFunction +} + + +/** + * Verifies that if an additional image is added after start() was called, but + * before COMPLETE was dispatched, no COMPLETE event is sent. Verifies COMPLETE + * is finally sent when .start() is called again and all images have now + * completed loading. + */ +function testImagesAddedAfterStart() { + // Use synchronous image loading. + makeLoaderSynchronous(loader); + + // Add another image once the first images finishes loading. + goog.events.listenOnce(loader, goog.events.EventType.LOAD, function() { + loader.addImage('extra_image', 'extra_image.gif'); + }); + + // Keep track of the total # of image loads. + var loadRecordFn = goog.testing.recordFunction(); + goog.events.listen(loader, goog.events.EventType.LOAD, loadRecordFn); + + // Keep track of how many times COMPLETE was dispatched. + var completeRecordFn = goog.testing.recordFunction(); + goog.events.listen(loader, goog.net.EventType.COMPLETE, completeRecordFn); + + // Start testing. + loader.start(); + assertEquals( + 'COMPLETE event should not have been dispatched yet: An image was ' + + 'added after the initial batch was started.', + 0, completeRecordFn.getCallCount()); + assertEquals('Just the test images should have loaded', + goog.object.getCount(TEST_IMAGES), loadRecordFn.getCallCount()); + + loader.start(); + assertEquals('COMPLETE should have been dispatched once.', + 1, completeRecordFn.getCallCount()); + assertEquals('All images should have been loaded', + goog.object.getCount(TEST_IMAGES) + 1, loadRecordFn.getCallCount()); +} + + +/** + * Verifies that more images can be added after an upload starts, and start() + * can be called for them, resulting in just one COMPLETE event once all the + * images have completed. + */ +function testImagesAddedAndStartedAfterStart() { + // Use synchronous image loading. + makeLoaderSynchronous(loader); + + // Keep track of the total # of image loads. + var loadRecordFn = goog.testing.recordFunction(); + goog.events.listen(loader, goog.events.EventType.LOAD, loadRecordFn); + + // Add more images once the first images finishes loading, and call start() + // to get them going. + goog.events.listenOnce(loader, goog.events.EventType.LOAD, function(e) { + loader.addImage('extra_image', 'extra_image.gif'); + loader.addImage('extra_image2', 'extra_image2.gif'); + loader.start(); + }); + + // Keep track of how many times COMPLETE was dispatched. + var completeRecordFn = goog.testing.recordFunction(); + goog.events.listen(loader, goog.net.EventType.COMPLETE, completeRecordFn); + + // Start testing. Make sure all 7 images loaded. + loader.start(); + assertEquals('COMPLETE should have been dispatched once.', + 1, completeRecordFn.getCallCount()); + assertEquals('All images should have been loaded', + goog.object.getCount(TEST_IMAGES) + 2, loadRecordFn.getCallCount()); +} + + +/** + * Verifies that if images are removed after loading has started, COMPLETE + * is dispatched once the remaining images have finished. + */ +function testImagesRemovedAfterStart() { + // Use synchronous image loading. + makeLoaderSynchronous(loader); + + // Remove 2 images once the first image finishes loading. + goog.events.listenOnce(loader, goog.events.EventType.LOAD, function(e) { + loader.removeImage( + goog.array.peek(goog.object.getKeys(this.imageIdToUrlMap_))); + loader.removeImage( + goog.array.peek(goog.object.getKeys(this.imageIdToUrlMap_))); + }); + + // Keep track of the total # of image loads. + var loadRecordFn = goog.testing.recordFunction(); + goog.events.listen(loader, goog.events.EventType.LOAD, loadRecordFn); + + // Keep track of how many times COMPLETE was dispatched. + var completeRecordFn = goog.testing.recordFunction(); + goog.events.listen(loader, goog.net.EventType.COMPLETE, completeRecordFn); + + // Start testing. Make sure only the 3 images remaining loaded. + loader.start(); + assertEquals('COMPLETE should have been dispatched once.', + 1, completeRecordFn.getCallCount()); + assertEquals('All images should have been loaded', + goog.object.getCount(TEST_IMAGES) - 2, loadRecordFn.getCallCount()); +} </script> </body> diff --git a/contexts/data/lib/closure-library/closure/goog/net/ipaddress.js b/contexts/data/lib/closure-library/closure/goog/net/ipaddress.js index 43f46b5..ef01ad5 100644 --- a/contexts/data/lib/closure-library/closure/goog/net/ipaddress.js +++ b/contexts/data/lib/closure-library/closure/goog/net/ipaddress.js @@ -98,6 +98,7 @@ goog.net.IpAddress.prototype.toUriString = goog.abstractMethod; /** * @return {string} The IP Address, as a string. + * @override */ goog.net.IpAddress.prototype.toString = goog.abstractMethod; diff --git a/contexts/data/lib/closure-library/closure/goog/net/jsloader.js b/contexts/data/lib/closure-library/closure/goog/net/jsloader.js index 653b205..5c28835 100644 --- a/contexts/data/lib/closure-library/closure/goog/net/jsloader.js +++ b/contexts/data/lib/closure-library/closure/goog/net/jsloader.js @@ -13,8 +13,8 @@ // limitations under the License. /** - * @fileoverview A utility to load JavaScript files. - * Refactored from goog.net.Jsonp. + * @fileoverview A utility to load JavaScript files via DOM script tags. + * Refactored from goog.net.Jsonp. Works cross-domain. * */ @@ -73,7 +73,18 @@ goog.net.jsloader.scriptsToLoad_ = []; /** - * Loads and evaluates the JavaScript files at the specified URIs, in order. + * Loads and evaluates the JavaScript files at the specified URIs, guaranteeing + * the order of script loads. + * + * Because we have to load the scripts in serial (load script 1, exec script 1, + * load script 2, exec script 2, and so on), this will be slower than doing + * the network fetches in parallel. + * + * If you need to load a large number of scripts but dependency order doesn't + * matter, you should just call goog.net.jsloader.load N times. + * + * If you need to load a large number of scripts on the same domain, + * you may want to use goog.module.ModuleLoader. * * @param {Array.<string>} uris The URIs to load. * @param {goog.net.jsloader.Options=} opt_options Optional parameters. See @@ -90,34 +101,24 @@ goog.net.jsloader.loadMany = function(uris, opt_options) { return; } - if (goog.userAgent.GECKO && !goog.userAgent.isVersion(2)) { - // For <script> tags that are loaded in this manner, Gecko 1.9 and earlier - // ensures that tag order is consistent with evaluation order. - // Unfortunately, other browsers do not make that guarantee. So the other - // browsers need a slower and more complex implementation. - for (var i = 0; i < uris.length; i++) { - goog.net.jsloader.load(uris[i], opt_options); - } - } else { - var isAnotherModuleLoading = goog.net.jsloader.scriptsToLoad_.length; - goog.array.extend(goog.net.jsloader.scriptsToLoad_, uris); - if (isAnotherModuleLoading) { - // jsloader is still loading some other scripts. - // In order to prevent the race condition noted above, we just add - // these URIs to the end of the scripts' queue and return. - return; - } - - uris = goog.net.jsloader.scriptsToLoad_; - var popAndLoadNextScript = function() { - var uri = uris.shift(); - var deferred = goog.net.jsloader.load(uri, opt_options); - if (uris.length) { - deferred.addBoth(popAndLoadNextScript); - } - }; - popAndLoadNextScript(); + var isAnotherModuleLoading = goog.net.jsloader.scriptsToLoad_.length; + goog.array.extend(goog.net.jsloader.scriptsToLoad_, uris); + if (isAnotherModuleLoading) { + // jsloader is still loading some other scripts. + // In order to prevent the race condition noted above, we just add + // these URIs to the end of the scripts' queue and return. + return; } + + uris = goog.net.jsloader.scriptsToLoad_; + var popAndLoadNextScript = function() { + var uri = uris.shift(); + var deferred = goog.net.jsloader.load(uri, opt_options); + if (uris.length) { + deferred.addBoth(popAndLoadNextScript); + } + }; + popAndLoadNextScript(); }; diff --git a/contexts/data/lib/closure-library/closure/goog/net/jsonp.js b/contexts/data/lib/closure-library/closure/goog/net/jsonp.js index 5276a70..814591a 100644 --- a/contexts/data/lib/closure-library/closure/goog/net/jsonp.js +++ b/contexts/data/lib/closure-library/closure/goog/net/jsonp.js @@ -181,8 +181,6 @@ goog.net.Jsonp.prototype.send = function(opt_payload, goog.global[goog.net.Jsonp.CALLBACKS] = {}; } - var script = goog.dom.createElement('script'); - // Create a new Uri object onto which this payload will be added var uri = this.uri_.clone(); if (payload) { diff --git a/contexts/data/lib/closure-library/closure/goog/net/testdata/.svn/all-wcprops b/contexts/data/lib/closure-library/closure/goog/net/testdata/.svn/all-wcprops deleted file mode 100644 index 4ba95ef..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/testdata/.svn/all-wcprops +++ /dev/null @@ -1,29 +0,0 @@ -K 25 -svn:wc:ra_dav:version-url -V 50 -/svn/!svn/ver/1452/trunk/closure/goog/net/testdata -END -jsloader_test2.js -K 25 -svn:wc:ra_dav:version-url -V 68 -/svn/!svn/ver/1452/trunk/closure/goog/net/testdata/jsloader_test2.js -END -jsloader_test3.js -K 25 -svn:wc:ra_dav:version-url -V 68 -/svn/!svn/ver/1452/trunk/closure/goog/net/testdata/jsloader_test3.js -END -jsloader_test4.js -K 25 -svn:wc:ra_dav:version-url -V 68 -/svn/!svn/ver/1452/trunk/closure/goog/net/testdata/jsloader_test4.js -END -jsloader_test1.js -K 25 -svn:wc:ra_dav:version-url -V 68 -/svn/!svn/ver/1452/trunk/closure/goog/net/testdata/jsloader_test1.js -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/testdata/.svn/entries b/contexts/data/lib/closure-library/closure/goog/net/testdata/.svn/entries deleted file mode 100644 index 621ed39..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/testdata/.svn/entries +++ /dev/null @@ -1,164 +0,0 @@ -10 - -dir -1494 -http://closure-library.googlecode.com/svn/trunk/closure/goog/net/testdata -http://closure-library.googlecode.com/svn - - - -2011-12-07T06:16:31.000000Z -1452 -ebixon@google.com - - - - - - - - - - - - - - -0b95b8e8-c90f-11de-9d4f-f947ee5921c8 - -jsloader_test2.js -file - - - - -2011-12-23T22:42:29.998349Z -29e0eb8361ec520d2125352209589461 -2011-12-07T06:16:31.000000Z -1452 -ebixon@google.com -has-props - - - - - - - - - - - - - - - - - - - - -845 - -jsloader_test3.js -file - - - - -2011-12-23T22:42:29.998349Z -9e3bb1fbfe7ca1a8b70b7339bb6e0154 -2011-12-07T06:16:31.000000Z -1452 -ebixon@google.com -has-props - - - - - - - - - - - - - - - - - - - - -828 - -jsloader_test4.js -file - - - - -2011-12-23T22:42:29.998349Z -3415399ba68ff9ed965da1d849279faf -2011-12-07T06:16:31.000000Z -1452 -ebixon@google.com -has-props - - - - - - - - - - - - - - - - - - - - -828 - -jsloader_test1.js -file - - - - -2011-12-23T22:42:29.999349Z -dffdc3191af40222534b3cca3b48bec9 -2011-12-07T06:16:31.000000Z -1452 -ebixon@google.com -has-props - - - - - - - - - - - - - - - - - - - - -821 - diff --git a/contexts/data/lib/closure-library/closure/goog/net/testdata/.svn/prop-base/jsloader_test1.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/testdata/.svn/prop-base/jsloader_test1.js.svn-base deleted file mode 100644 index 530636b..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/testdata/.svn/prop-base/jsloader_test1.js.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 15 -text/javascript -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/testdata/.svn/prop-base/jsloader_test2.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/testdata/.svn/prop-base/jsloader_test2.js.svn-base deleted file mode 100644 index 530636b..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/testdata/.svn/prop-base/jsloader_test2.js.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 15 -text/javascript -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/testdata/.svn/prop-base/jsloader_test3.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/testdata/.svn/prop-base/jsloader_test3.js.svn-base deleted file mode 100644 index 530636b..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/testdata/.svn/prop-base/jsloader_test3.js.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 15 -text/javascript -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/testdata/.svn/prop-base/jsloader_test4.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/testdata/.svn/prop-base/jsloader_test4.js.svn-base deleted file mode 100644 index 530636b..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/testdata/.svn/prop-base/jsloader_test4.js.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 15 -text/javascript -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/testdata/.svn/text-base/jsloader_test1.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/testdata/.svn/text-base/jsloader_test1.js.svn-base deleted file mode 100644 index 59d2162..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/testdata/.svn/text-base/jsloader_test1.js.svn-base +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2011 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// All Rights Reserved - -/** - * @fileoverview Test #1 of jsloader. - */ - -goog.provide('goog.net.testdata.jsloader_test1'); -goog.setTestOnly('jsloader_test1'); - -window['test1'] = 'Test #1 loaded'; diff --git a/contexts/data/lib/closure-library/closure/goog/net/testdata/.svn/text-base/jsloader_test2.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/testdata/.svn/text-base/jsloader_test2.js.svn-base deleted file mode 100644 index 8690539..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/testdata/.svn/text-base/jsloader_test2.js.svn-base +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2011 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// All Rights Reserved - -/** - * @fileoverview Test #2 of jsloader. - */ - -goog.provide('goog.net.testdata.jsloader_test2'); -goog.setTestOnly('jsloader_test2'); - -window['closure_verification']['test2'] = 'Test #2 loaded'; diff --git a/contexts/data/lib/closure-library/closure/goog/net/testdata/.svn/text-base/jsloader_test3.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/testdata/.svn/text-base/jsloader_test3.js.svn-base deleted file mode 100644 index 7c1181d..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/testdata/.svn/text-base/jsloader_test3.js.svn-base +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2011 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// All Rights Reserved - -/** - * @fileoverview Test #3 of jsloader. - */ - -goog.provide('goog.net.testdata.jsloader_test3'); -goog.setTestOnly('jsloader_test3'); - -window['test3Callback']('Test #3 loaded'); diff --git a/contexts/data/lib/closure-library/closure/goog/net/testdata/.svn/text-base/jsloader_test4.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/testdata/.svn/text-base/jsloader_test4.js.svn-base deleted file mode 100644 index 591209c..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/testdata/.svn/text-base/jsloader_test4.js.svn-base +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2011 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// All Rights Reserved - -/** - * @fileoverview Test #4 of jsloader. - */ - -goog.provide('goog.net.testdata.jsloader_test4'); -goog.setTestOnly('jsloader_test4'); - -window['test4Callback']('Test #4 loaded'); diff --git a/contexts/data/lib/closure-library/closure/goog/net/xhrio.js b/contexts/data/lib/closure-library/closure/goog/net/xhrio.js index 09e30fa..c12cecb 100644 --- a/contexts/data/lib/closure-library/closure/goog/net/xhrio.js +++ b/contexts/data/lib/closure-library/closure/goog/net/xhrio.js @@ -88,7 +88,7 @@ goog.inherits(goog.net.XhrIo, goog.events.EventTarget); /** * Response types that may be requested for XMLHttpRequests. * @enum {string} - * @see http://dev.w3.org/2006/webapi/XMLHttpRequest-2/#the-responsetype-attribute + * @see http://www.w3.org/TR/XMLHttpRequest/#the-responsetype-attribute */ goog.net.XhrIo.ResponseType = { DEFAULT: '', @@ -149,8 +149,9 @@ goog.net.XhrIo.sendInstances_ = []; * @param {Function=} opt_callback Callback function for when request is * complete. * @param {string=} opt_method Send method, default: GET. - * @param {string|GearsBlob=} opt_content Post data. This can be a Gears blob - * if the underlying HTTP request object is a Gears HTTP request. + * @param {string|FormData|GearsBlob=} opt_content + * Post data. This can be a Gears blob if the underlying HTTP request object + * is a Gears HTTP request. * @param {Object|goog.structs.Map=} opt_headers Map of headers to add to the * request. * @param {number=} opt_timeoutInterval Number of milliseconds after which an @@ -356,7 +357,7 @@ goog.net.XhrIo.prototype.responseType_ = goog.net.XhrIo.ResponseType.DEFAULT; * more recent browsers that support this part of the HTTP Access Control * standard. * - * @see http://dev.w3.org/2006/webapi/XMLHttpRequest-2/#withcredentials + * @see http://www.w3.org/TR/XMLHttpRequest/#the-withcredentials-attribute * * @type {boolean} * @private @@ -434,15 +435,17 @@ goog.net.XhrIo.prototype.getWithCredentials = function() { * Instance send that actually uses XMLHttpRequest to make a server call. * @param {string|goog.Uri} url Uri to make request to. * @param {string=} opt_method Send method, default: GET. - * @param {string|GearsBlob=} opt_content Post data. This can be a Gears blob - * if the underlying HTTP request object is a Gears HTTP request. + * @param {string|FormData|GearsBlob=} opt_content + * Post data. This can be a Gears blob if the underlying HTTP request object + * is a Gears HTTP request. * @param {Object|goog.structs.Map=} opt_headers Map of headers to add to the * request. */ goog.net.XhrIo.prototype.send = function(url, opt_method, opt_content, opt_headers) { if (this.xhr_) { - throw Error('[goog.net.XhrIo] Object is active with another request'); + throw Error('[goog.net.XhrIo] Object is active with another request=' + + this.lastUri_ + '; newUri=' + url); } var method = opt_method ? opt_method.toUpperCase() : 'GET'; @@ -491,9 +494,15 @@ goog.net.XhrIo.prototype.send = function(url, opt_method, opt_content, }); } + var contentIsFormData = (goog.global['FormData'] && + (content instanceof goog.global['FormData'])); if (method == 'POST' && - !headers.containsKey(goog.net.XhrIo.CONTENT_TYPE_HEADER)) { - // For POST requests, default to the url-encoded form content type. + !headers.containsKey(goog.net.XhrIo.CONTENT_TYPE_HEADER) && + !contentIsFormData) { + // For POST requests, default to the url-encoded form content type + // unless this is a FormData request. For FormData, the browser will + // automatically add a multipart/form-data content type with an appropriate + // multipart boundary. headers.set(goog.net.XhrIo.CONTENT_TYPE_HEADER, goog.net.XhrIo.FORM_CONTENT_TYPE); } @@ -729,18 +738,21 @@ goog.net.XhrIo.prototype.onReadyStateChangeHelper_ = function() { this.active_ = false; - // Call the specific callbacks for success or failure. Only call the - // success if the status is 200 (HTTP_OK) or 304 (HTTP_CACHED) - if (this.isSuccess()) { - this.dispatchEvent(goog.net.EventType.COMPLETE); - this.dispatchEvent(goog.net.EventType.SUCCESS); - } else { - this.lastErrorCode_ = goog.net.ErrorCode.HTTP_ERROR; - this.lastError_ = this.getStatusText() + ' [' + this.getStatus() + ']'; - this.dispatchErrors_(); + try { + // Call the specific callbacks for success or failure. Only call the + // success if the status is 200 (HTTP_OK) or 304 (HTTP_CACHED) + if (this.isSuccess()) { + this.dispatchEvent(goog.net.EventType.COMPLETE); + this.dispatchEvent(goog.net.EventType.SUCCESS); + } else { + this.lastErrorCode_ = goog.net.ErrorCode.HTTP_ERROR; + this.lastError_ = + this.getStatusText() + ' [' + this.getStatus() + ']'; + this.dispatchErrors_(); + } + } finally { + this.cleanUpXhr_(); } - - this.cleanUpXhr_(); } } }; @@ -961,7 +973,7 @@ goog.net.XhrIo.prototype.getResponseJson = function(opt_xssiPrefix) { * try to emulate it. * * Emulating the response means following the rules laid out at - * http://dev.w3.org/2006/webapi/XMLHttpRequest-2/#the-response-attribute. + * http://www.w3.org/TR/XMLHttpRequest/#the-response-attribute * * On browsers with no support for this (Chrome < 10, Firefox < 4, etc), only * response types of DEFAULT or TEXT may be used, and the response returned will diff --git a/contexts/data/lib/closure-library/closure/goog/net/xhrio_test.html b/contexts/data/lib/closure-library/closure/goog/net/xhrio_test.html index 096f8f6..a78eaf2 100644 --- a/contexts/data/lib/closure-library/closure/goog/net/xhrio_test.html +++ b/contexts/data/lib/closure-library/closure/goog/net/xhrio_test.html @@ -21,6 +21,7 @@ See the COPYING file for details. goog.require('goog.object'); goog.require('goog.string'); goog.require('goog.testing.MockClock'); + goog.require('goog.testing.PropertyReplacer'); goog.require('goog.testing.jsunit'); goog.require('goog.testing.net.XhrIo'); goog.require('goog.testing.recordFunction'); @@ -34,6 +35,8 @@ MockXmlHttp.prototype.readyState = goog.net.XmlHttp.ReadyState.UNINITIALIZED; MockXmlHttp.prototype.status = 200; +MockXmlHttp.prototype.headers = {}; + MockXmlHttp.syncSend = false; MockXmlHttp.prototype.send = function(opt_data) { @@ -65,7 +68,9 @@ MockXmlHttp.prototype.open = function(verb, uri, async) { MockXmlHttp.prototype.abort = function() {}; -MockXmlHttp.prototype.setRequestHeader = function(key, value) {}; +MockXmlHttp.prototype.setRequestHeader = function(key, value) { + this.headers[key] = value; +}; var lastMockXmlHttp; goog.net.XmlHttp.setGlobalFactory(new goog.net.WrapperXmlHttpFactory( @@ -78,6 +83,7 @@ goog.net.XmlHttp.setGlobalFactory(new goog.net.WrapperXmlHttpFactory( })); +var propertyReplacer = new goog.testing.PropertyReplacer(); var clock; var originalEntryPoint = goog.net.XhrIo.prototype.onReadyStateChangeEntryPoint_; @@ -88,6 +94,7 @@ function setUp() { } function tearDown() { + propertyReplacer.reset(); clock.dispose(); goog.net.XhrIo.prototype.onReadyStateChangeEntryPoint_ = originalEntryPoint; } @@ -413,8 +420,8 @@ function testSendFromListener() { var e = assertThrows(function() { x.send('url2'); }); - assertEquals('[goog.net.XhrIo] Object is active with another request', - e.message); + assertEquals('[goog.net.XhrIo] Object is active with another request=url' + + '; newUri=url2', e.message); }); x.send('url'); @@ -479,6 +486,24 @@ function testProtectEntryPointCalledOnAsyncSend() { errorHandlerCallbackCalled); } +function testXHRIsDiposedEvenIfAListenerThrowsAnExceptionOnComplete() { + MockXmlHttp.syncSend = false; + + var x = new goog.net.XhrIo; + + goog.events.listen(x, goog.net.EventType.COMPLETE, function(e) { + throw Error(); + }, false, x); + + x.send('url'); + assertThrows(function() { + lastMockXmlHttp.complete(); + }); + + // The XHR should have been disposed, even though the listener threw an + // exception. + assertNull(x.xhr_); +} function testDisposeInternalDoesNotAbortXhrRequestObjectWhenActiveIsFalse() { MockXmlHttp.syncSend = false; @@ -510,6 +535,28 @@ function testCallingAbortFromWithinAbortCallbackDoesntLoop() { x.abort(); } +function testPostSetsContentTypeHeader() { + var x = new goog.net.XhrIo; + + x.send('url', 'POST', 'content'); + var headers = lastMockXmlHttp.headers; + assertEquals(1, goog.object.getCount(headers)); + assertEquals( + headers[goog.net.XhrIo.CONTENT_TYPE_HEADER], + goog.net.XhrIo.FORM_CONTENT_TYPE); +} + +function testPostFormDataDoesNotSetContentTypeHeader() { + function FakeFormData() {} + + propertyReplacer.set(goog.global, 'FormData', FakeFormData); + + var x = new goog.net.XhrIo; + x.send('url', 'POST', new FakeFormData()); + var headers = lastMockXmlHttp.headers; + assertTrue(goog.object.isEmpty(headers)); +} + function testFactoryInjection() { var xhr = new MockXmlHttp(); var optionsFactoryCalled = 0; diff --git a/contexts/data/lib/closure-library/closure/goog/net/xhriopool.js b/contexts/data/lib/closure-library/closure/goog/net/xhriopool.js index 1b2e171..ecbfca6 100644 --- a/contexts/data/lib/closure-library/closure/goog/net/xhriopool.js +++ b/contexts/data/lib/closure-library/closure/goog/net/xhriopool.js @@ -52,6 +52,7 @@ goog.inherits(goog.net.XhrIoPool, goog.structs.PriorityPool); /** * Creates an instance of an XhrIo object to use in the pool. * @return {goog.net.XhrIo} The created object. + * @override */ goog.net.XhrIoPool.prototype.createObject = function() { var xhrIo = new goog.net.XhrIo(); @@ -66,22 +67,14 @@ goog.net.XhrIoPool.prototype.createObject = function() { /** - * Should be overridden to dispose of an object, default implementation is to - * remove all its members which should render it useless. - * @param {goog.net.XhrIo} obj The object to dispose. - */ -goog.net.XhrIoPool.prototype.disposeObject = function(obj) { - obj.dispose(); -}; - - -/** * Determine if an object has become unusable and should not be used. - * @param {goog.net.XhrIo} obj The object to test. + * @param {Object} obj The object to test. * @return {boolean} Whether the object can be reused, which is true if the * object is not disposed and not active. + * @override */ goog.net.XhrIoPool.prototype.objectCanBeReused = function(obj) { // An active XhrIo object should never be used. - return !obj.isDisposed() && !obj.isActive(); + var xhr = /** @type {goog.net.XhrIo} */ (obj); + return !xhr.isDisposed() && !xhr.isActive(); }; diff --git a/contexts/data/lib/closure-library/closure/goog/net/xhrmanager.js b/contexts/data/lib/closure-library/closure/goog/net/xhrmanager.js index 36339f4..d7b786b 100644 --- a/contexts/data/lib/closure-library/closure/goog/net/xhrmanager.js +++ b/contexts/data/lib/closure-library/closure/goog/net/xhrmanager.js @@ -139,7 +139,9 @@ goog.net.XhrManager.prototype.setTimeoutInterval = function(ms) { /** - * Returns the number of reuqests either in flight, or waiting to be sent. + * Returns the number of requests either in flight, or waiting to be sent. + * The count will include the current request if used within a COMPLETE event + * handler or callback. * @return {number} The number of requests in flight or pending send. */ goog.net.XhrManager.prototype.getOutstandingCount = function() { @@ -148,6 +150,17 @@ goog.net.XhrManager.prototype.getOutstandingCount = function() { /** + * Returns an array of request ids that are either in flight, or waiting to + * be sent. The id of the current request will be included if used within a + * COMPLETE event handler or callback. + * @return {!Array.<string>} Request ids in flight or pending send. + */ +goog.net.XhrManager.prototype.getOutstandingRequestIds = function() { + return this.requests_.getKeys(); +}; + + +/** * Registers the given request to be sent. Throws an error if a request * already exists with the given ID. * NOTE: It is not sent immediately. It is queued and will be sent when an @@ -159,11 +172,14 @@ goog.net.XhrManager.prototype.getOutstandingCount = function() { * @param {string=} opt_content Post data. * @param {Object|goog.structs.Map=} opt_headers Map of headers to add to the * request. - * @param {*=} opt_priority The priority of the request. + * @param {*=} opt_priority The priority of the request. A smaller value means a + * higher priority. * @param {Function=} opt_callback Callback function for when request is * complete. The only param is the event object from the COMPLETE event. * @param {number=} opt_maxRetries The maximum number of times the request * should be retried. + * @param {goog.net.XhrIo.ResponseType=} opt_responseType The response type of + * this request; defaults to goog.net.XhrIo.ResponseType.DEFAULT. * @return {goog.net.XhrManager.Request} The queued request object. */ goog.net.XhrManager.prototype.send = function( @@ -174,7 +190,8 @@ goog.net.XhrManager.prototype.send = function( opt_headers, opt_priority, opt_callback, - opt_maxRetries) { + opt_maxRetries, + opt_responseType) { var requests = this.requests_; // Check if there is already a request with the given id. if (requests.get(id)) { @@ -189,7 +206,8 @@ goog.net.XhrManager.prototype.send = function( opt_content, opt_headers, opt_callback, - goog.isDef(opt_maxRetries) ? opt_maxRetries : this.maxRetries_); + goog.isDef(opt_maxRetries) ? opt_maxRetries : this.maxRetries_, + opt_responseType); this.requests_.set(id, request); // Setup the callback for the pool. @@ -212,15 +230,17 @@ goog.net.XhrManager.prototype.abort = function(id, opt_force) { var xhrIo = request.xhrIo; request.setAborted(true); if (opt_force) { - // We remove listeners to make sure nothing gets called if a new request - // with the same id is made. - this.removeXhrListener_(xhrIo, request.getXhrEventCallback()); - goog.events.listenOnce( - xhrIo, - goog.net.EventType.READY, - function() { this.xhrPool_.releaseObject(xhrIo); }, - false, - this); + if (xhrIo) { + // We remove listeners to make sure nothing gets called if a new request + // with the same id is made. + this.removeXhrListener_(xhrIo, request.getXhrEventCallback()); + goog.events.listenOnce( + xhrIo, + goog.net.EventType.READY, + function() { this.xhrPool_.releaseObject(xhrIo); }, + false, + this); + } this.requests_.remove(id); } if (xhrIo) { @@ -247,6 +267,7 @@ goog.net.XhrManager.prototype.handleAvailableXhr_ = function(id, xhrIo) { // Set properties for the XhrIo. xhrIo.setTimeoutInterval(this.timeoutInterval_); + xhrIo.setResponseType(request.getResponseType()); // Add a reference to the XhrIo object to the request. request.xhrIo = request.xhrLite = xhrIo; @@ -511,10 +532,6 @@ goog.inherits(goog.net.XhrManager.Event, goog.events.Event); /** @override */ goog.net.XhrManager.Event.prototype.disposeInternal = function() { - goog.net.XhrManager.Event.superClass_.disposeInternal.call(this); - delete this.id; - this.xhrIo = null; - this.xhrLite = null; }; @@ -534,12 +551,14 @@ goog.net.XhrManager.Event.prototype.disposeInternal = function() { * complete. NOTE: Only 1 callback supported across all events. * @param {number=} opt_maxRetries The maximum number of times the request * should be retried (Default: 1). + * @param {goog.net.XhrIo.ResponseType=} opt_responseType The response type of + * this request; defaults to goog.net.XhrIo.ResponseType.DEFAULT. * * @constructor * @extends {goog.Disposable} */ goog.net.XhrManager.Request = function(url, xhrEventCallback, opt_method, - opt_content, opt_headers, opt_callback, opt_maxRetries) { + opt_content, opt_headers, opt_callback, opt_maxRetries, opt_responseType) { goog.Disposable.call(this); /** @@ -613,6 +632,13 @@ goog.net.XhrManager.Request = function(url, xhrEventCallback, opt_method, this.completeCallback_ = opt_callback; /** + * A response type to set on this.xhrIo when it's populated. + * @type {!goog.net.XhrIo.ResponseType} + * @private + */ + this.responseType_ = opt_responseType || goog.net.XhrIo.ResponseType.DEFAULT; + + /** * The XhrIo instance handling this request. Set in handleAvailableXhr. * @type {goog.net.XhrIo} */ @@ -749,6 +775,17 @@ goog.net.XhrManager.Request.prototype.getCompleteCallback = function() { }; +/** + * Gets the response type that will be set on this request's XhrIo when it's + * available. + * @return {!goog.net.XhrIo.ResponseType} The response type to be set + * when an XhrIo becomes available to this request. + */ +goog.net.XhrManager.Request.prototype.getResponseType = function() { + return this.responseType_; +}; + + /** @override */ goog.net.XhrManager.Request.prototype.disposeInternal = function() { goog.net.XhrManager.Request.superClass_.disposeInternal.call(this); diff --git a/contexts/data/lib/closure-library/closure/goog/net/xhrmanager_test.html b/contexts/data/lib/closure-library/closure/goog/net/xhrmanager_test.html new file mode 100644 index 0000000..81350e1 --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/net/xhrmanager_test.html @@ -0,0 +1,123 @@ +<!DOCTYPE html> +<html> +<!-- +Copyright 2012 The Closure Library Authors. All Rights Reserved. + +Use of this source code is governed by the Apache License, Version 2.0. +See the COPYING file for details. +--> +<!-- +--> +<head> +<meta http-equiv="X-UA-Compatible" content="IE=edge"> +<title>Closure Unit Tests - goog.net.XhrManager</title> +<script src="../base.js"></script> +<script> + goog.require('goog.events'); + goog.require('goog.net.EventType'); + goog.require('goog.net.XhrManager'); + goog.require('goog.testing.jsunit'); + goog.require('goog.testing.net.XhrIoPool'); + goog.require('goog.testing.recordFunction'); +</script> +</head> +<body> +<script> + + /** @type {goog.net.XhrManager} */ + var xhrManager + + /** @type {goog.testing.net.XhrIo} */ + var xhrIo; + + + function setUp() { + xhrManager = new goog.net.XhrManager(); + xhrManager.xhrPool_ = new goog.testing.net.XhrIoPool(); + xhrIo = xhrManager.xhrPool_.getXhr(); + } + + + function tearDown() { + goog.dispose(xhrManager); + } + + + function testGetOutstandingRequestIds() { + assertArrayEquals( + 'No outstanding requests', [], xhrManager.getOutstandingRequestIds()); + + xhrManager.send('test1', '/test1'); + assertArrayEquals( + 'Single outstanding request', ['test1'], + xhrManager.getOutstandingRequestIds()); + + xhrManager.send('test2', '/test2'); + assertArrayEquals( + 'Two outstanding requests', ['test1', 'test2'], + xhrManager.getOutstandingRequestIds()); + + xhrIo.simulateResponse(200, 'data'); + assertArrayEquals( + 'Single outstanding request', ['test2'], + xhrManager.getOutstandingRequestIds()); + + xhrIo.simulateResponse(200, 'data'); + assertArrayEquals( + 'No outstanding requests', [], xhrManager.getOutstandingRequestIds()); + } + + + function testForceAbortQueuedRequest() { + xhrManager.send('test', '/test'); + xhrManager.send('queued', '/queued'); + + assertNotThrows( + 'Forced abort of queued request should not throw an error', + goog.bind(xhrManager.abort, xhrManager, 'queued', true)); + + assertNotThrows( + 'Forced abort of normal request should not throw an error', + goog.bind(xhrManager.abort, xhrManager, 'test', true)); + } + + + function testDefaultResponseType() { + var callback = goog.testing.recordFunction(function(e) { + assertEquals('test1', e.id); + assertEquals( + goog.net.XhrIo.ResponseType.DEFAULT, e.xhrIo.getResponseType()); + eventCalled = true; + }); + goog.events.listenOnce(xhrManager, goog.net.EventType.READY, callback); + xhrManager.send('test1', '/test2'); + assertEquals(1, callback.getCallCount()); + + xhrIo.simulateResponse(200, 'data'); // Do this to make tearDown() happy. + } + + + function testNonDefaultResponseType() { + var callback = goog.testing.recordFunction(function(e) { + assertEquals('test2', e.id); + assertEquals( + goog.net.XhrIo.ResponseType.ARRAY_BUFFER, e.xhrIo.getResponseType()); + eventCalled = true; + }); + goog.events.listenOnce(xhrManager, goog.net.EventType.READY, callback); + xhrManager.send('test2', '/test2', + undefined /* opt_method */, + undefined /* opt_content */, + undefined /* opt_headers */, + undefined /* opt_priority */, + undefined /* opt_callback */, + undefined /* opt_maxRetries */, + goog.net.XhrIo.ResponseType.ARRAY_BUFFER); + assertEquals(1, callback.getCallCount()); + + xhrIo.simulateResponse(200, 'data'); // Do this to make tearDown() happy. + } + +</script> +</body> +</html> diff --git a/contexts/data/lib/closure-library/closure/goog/net/xmlhttp.js b/contexts/data/lib/closure-library/closure/goog/net/xmlhttp.js index da85a65..da64e9f 100644 --- a/contexts/data/lib/closure-library/closure/goog/net/xmlhttp.js +++ b/contexts/data/lib/closure-library/closure/goog/net/xmlhttp.js @@ -37,6 +37,13 @@ goog.net.XmlHttp = function() { /** + * @define {boolean} Whether to assume XMLHttpRequest exists. Setting this to + * true strips the ActiveX probing code. + */ +goog.net.XmlHttp.ASSUME_NATIVE_XHR = false; + + +/** * Gets the options to use with the XMLHttpRequest objects obtained using * the static methods. * @return {Object} The options. @@ -168,10 +175,10 @@ goog.net.DefaultXmlHttpFactory.prototype.internalGetOptions = function() { /** * The ActiveX PROG ID string to use to create xhr's in IE. Lazily initialized. - * @type {?string} + * @type {string|undefined} * @private */ -goog.net.DefaultXmlHttpFactory.prototype.ieProgId_ = null; +goog.net.DefaultXmlHttpFactory.prototype.ieProgId_; /** @@ -180,6 +187,10 @@ goog.net.DefaultXmlHttpFactory.prototype.ieProgId_ = null; * @private */ goog.net.DefaultXmlHttpFactory.prototype.getProgId_ = function() { + if (goog.net.XmlHttp.ASSUME_NATIVE_XHR) { + return ''; + } + // The following blog post describes what PROG IDs to use to create the // XMLHTTP object in Internet Explorer: // http://blogs.msdn.com/xmlteam/archive/2006/10/23/using-the-right-version-of-msxml-in-internet-explorer.aspx diff --git a/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/all-wcprops b/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/all-wcprops deleted file mode 100644 index bdcf701..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/all-wcprops +++ /dev/null @@ -1,77 +0,0 @@ -K 25 -svn:wc:ra_dav:version-url -V 45 -/svn/!svn/ver/1477/trunk/closure/goog/net/xpc -END -iframepollingtransport.js -K 25 -svn:wc:ra_dav:version-url -V 71 -/svn/!svn/ver/1362/trunk/closure/goog/net/xpc/iframepollingtransport.js -END -crosspagechannel_test.html -K 25 -svn:wc:ra_dav:version-url -V 72 -/svn/!svn/ver/1302/trunk/closure/goog/net/xpc/crosspagechannel_test.html -END -nativemessagingtransport_test.html -K 25 -svn:wc:ra_dav:version-url -V 80 -/svn/!svn/ver/1122/trunk/closure/goog/net/xpc/nativemessagingtransport_test.html -END -xpc.js -K 25 -svn:wc:ra_dav:version-url -V 51 -/svn/!svn/ver/850/trunk/closure/goog/net/xpc/xpc.js -END -nixtransport.js -K 25 -svn:wc:ra_dav:version-url -V 61 -/svn/!svn/ver/1302/trunk/closure/goog/net/xpc/nixtransport.js -END -transport.js -K 25 -svn:wc:ra_dav:version-url -V 58 -/svn/!svn/ver/1020/trunk/closure/goog/net/xpc/transport.js -END -relay.js -K 25 -svn:wc:ra_dav:version-url -V 53 -/svn/!svn/ver/850/trunk/closure/goog/net/xpc/relay.js -END -iframerelaytransport.js -K 25 -svn:wc:ra_dav:version-url -V 69 -/svn/!svn/ver/1302/trunk/closure/goog/net/xpc/iframerelaytransport.js -END -crosspagechannel.js -K 25 -svn:wc:ra_dav:version-url -V 65 -/svn/!svn/ver/1477/trunk/closure/goog/net/xpc/crosspagechannel.js -END -nativemessagingtransport.js -K 25 -svn:wc:ra_dav:version-url -V 73 -/svn/!svn/ver/1302/trunk/closure/goog/net/xpc/nativemessagingtransport.js -END -crosspagechannelrole.js -K 25 -svn:wc:ra_dav:version-url -V 69 -/svn/!svn/ver/1122/trunk/closure/goog/net/xpc/crosspagechannelrole.js -END -frameelementmethodtransport.js -K 25 -svn:wc:ra_dav:version-url -V 76 -/svn/!svn/ver/1302/trunk/closure/goog/net/xpc/frameelementmethodtransport.js -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/entries b/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/entries deleted file mode 100644 index 608c60c..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/entries +++ /dev/null @@ -1,439 +0,0 @@ -10 - -dir -1494 -http://closure-library.googlecode.com/svn/trunk/closure/goog/net/xpc -http://closure-library.googlecode.com/svn - - - -2011-12-14T19:06:32.000000Z -1477 -dpb@google.com - - - - - - - - - - - - - - -0b95b8e8-c90f-11de-9d4f-f947ee5921c8 - -iframepollingtransport.js -file - - - - -2011-12-23T22:42:30.163351Z -c62fdd9adccdf1db5738eb994d6d423a -2011-10-27T21:00:19.000000Z -1362 -junyin@google.com -has-props - - - - - - - - - - - - - - - - - - - - -25019 - -crosspagechannel_test.html -file - - - - -2011-12-23T22:42:30.164351Z -377b19f3f6438ec732b6562830399601 -2011-09-27T00:20:47.000000Z -1302 -bmccann@google.com -has-props - - - - - - - - - - - - - - - - - - - - -11801 - -nativemessagingtransport_test.html -file - - - - -2011-12-23T22:42:30.165351Z -381477fd2a0f9f8155f5dcef63e04063 -2011-07-13T22:50:38.000000Z -1122 -mknichel@google.com -has-props - - - - - - - - - - - - - - - - - - - - -4892 - -xpc.js -file - - - - -2011-12-23T22:42:30.165351Z -86f55130f1502a8761205ca0c029556e -2011-04-12T20:35:47.000000Z -850 -diegosalas@google.com -has-props - - - - - - - - - - - - - - - - - - - - -6184 - -nixtransport.js -file - - - - -2011-12-23T22:42:30.166351Z -e9e39d8a1754a26b504cfa3f2524a08d -2011-09-27T00:20:47.000000Z -1302 -bmccann@google.com -has-props - - - - - - - - - - - - - - - - - - - - -14881 - -transport.js -file - - - - -2011-12-23T22:42:30.167351Z -d86182105ba1f92fc5ada97d6d46108b -2011-06-09T19:55:41.000000Z -1020 -ivaylobakalov@google.com -has-props - - - - - - - - - - - - - - - - - - - - -2717 - -relay.js -file - - - - -2011-12-23T22:42:30.167351Z -3c3f467b3f3ee5808f93b7bc6f2385aa -2011-04-12T20:35:47.000000Z -850 -diegosalas@google.com -has-props - - - - - - - - - - - - - - - - - - - - -2201 - -iframerelaytransport.js -file - - - - -2011-12-23T22:42:30.168351Z -7ee604e01e9ef5a1680536b7cbb8f0e4 -2011-09-27T00:20:47.000000Z -1302 -bmccann@google.com -has-props - - - - - - - - - - - - - - - - - - - - -11612 - -testdata -dir - -crosspagechannel.js -file - - - - -2011-12-23T22:42:30.169351Z -09cb6b5db328c49d539274c3b1805819 -2011-12-14T19:06:32.000000Z -1477 -dpb@google.com -has-props - - - - - - - - - - - - - - - - - - - - -21370 - -nativemessagingtransport.js -file - - - - -2011-12-23T22:42:30.169351Z -c9bcc0a1161b7772cb8e3f52cc582d17 -2011-09-27T00:20:47.000000Z -1302 -bmccann@google.com -has-props - - - - - - - - - - - - - - - - - - - - -9836 - -crosspagechannelrole.js -file - - - - -2011-12-23T22:42:30.170351Z -9c07a99aa10ead74a5287bbd9b56ab32 -2011-07-13T22:50:38.000000Z -1122 -mknichel@google.com -has-props - - - - - - - - - - - - - - - - - - - - -881 - -frameelementmethodtransport.js -file - - - - -2011-12-23T22:42:30.171351Z -87e0ce3003224561c690fae06d2776c8 -2011-09-27T00:20:47.000000Z -1302 -bmccann@google.com -has-props - - - - - - - - - - - - - - - - - - - - -7318 - diff --git a/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/prop-base/crosspagechannel.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/prop-base/crosspagechannel.js.svn-base deleted file mode 100644 index 530636b..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/prop-base/crosspagechannel.js.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 15 -text/javascript -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/prop-base/crosspagechannel_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/prop-base/crosspagechannel_test.html.svn-base deleted file mode 100644 index d356868..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/prop-base/crosspagechannel_test.html.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 9 -text/html -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/prop-base/crosspagechannelrole.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/prop-base/crosspagechannelrole.js.svn-base deleted file mode 100644 index 530636b..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/prop-base/crosspagechannelrole.js.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 15 -text/javascript -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/prop-base/frameelementmethodtransport.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/prop-base/frameelementmethodtransport.js.svn-base deleted file mode 100644 index 530636b..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/prop-base/frameelementmethodtransport.js.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 15 -text/javascript -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/prop-base/iframepollingtransport.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/prop-base/iframepollingtransport.js.svn-base deleted file mode 100644 index 530636b..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/prop-base/iframepollingtransport.js.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 15 -text/javascript -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/prop-base/iframerelaytransport.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/prop-base/iframerelaytransport.js.svn-base deleted file mode 100644 index 530636b..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/prop-base/iframerelaytransport.js.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 15 -text/javascript -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/prop-base/nativemessagingtransport.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/prop-base/nativemessagingtransport.js.svn-base deleted file mode 100644 index 530636b..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/prop-base/nativemessagingtransport.js.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 15 -text/javascript -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/prop-base/nativemessagingtransport_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/prop-base/nativemessagingtransport_test.html.svn-base deleted file mode 100644 index d356868..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/prop-base/nativemessagingtransport_test.html.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 9 -text/html -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/prop-base/nixtransport.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/prop-base/nixtransport.js.svn-base deleted file mode 100644 index 530636b..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/prop-base/nixtransport.js.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 15 -text/javascript -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/prop-base/relay.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/prop-base/relay.js.svn-base deleted file mode 100644 index 530636b..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/prop-base/relay.js.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 15 -text/javascript -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/prop-base/transport.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/prop-base/transport.js.svn-base deleted file mode 100644 index 530636b..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/prop-base/transport.js.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 15 -text/javascript -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/prop-base/xpc.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/prop-base/xpc.js.svn-base deleted file mode 100644 index 530636b..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/prop-base/xpc.js.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 15 -text/javascript -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/text-base/crosspagechannel.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/text-base/crosspagechannel.js.svn-base deleted file mode 100644 index f14e95e..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/text-base/crosspagechannel.js.svn-base +++ /dev/null @@ -1,673 +0,0 @@ -// Copyright 2007 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Provides the class CrossPageChannel, the main class in - * goog.net.xpc. - * - * @see ../../demos/xpc/index.html - */ - -goog.provide('goog.net.xpc.CrossPageChannel'); - -goog.require('goog.Disposable'); -goog.require('goog.Uri'); -goog.require('goog.dom'); -goog.require('goog.events'); -goog.require('goog.json'); -goog.require('goog.messaging.AbstractChannel'); -goog.require('goog.net.xpc'); -goog.require('goog.net.xpc.CrossPageChannelRole'); -goog.require('goog.net.xpc.FrameElementMethodTransport'); -goog.require('goog.net.xpc.IframePollingTransport'); -goog.require('goog.net.xpc.IframeRelayTransport'); -goog.require('goog.net.xpc.NativeMessagingTransport'); -goog.require('goog.net.xpc.NixTransport'); -goog.require('goog.net.xpc.Transport'); -goog.require('goog.userAgent'); - - - -/** - * A communication channel between two documents from different domains. - * Provides asynchronous messaging. - * - * @param {Object} cfg Channel configuration object. - * @param {goog.dom.DomHelper=} opt_domHelper The optional dom helper to - * use for looking up elements in the dom. - * @constructor - * @extends {goog.messaging.AbstractChannel} - */ -goog.net.xpc.CrossPageChannel = function(cfg, opt_domHelper) { - goog.base(this); - - for (var i = 0, uriField; uriField = goog.net.xpc.UriCfgFields[i]; i++) { - if (uriField in cfg && !/^https?:\/\//.test(cfg[uriField])) { - throw Error('URI ' + cfg[uriField] + ' is invalid for field ' + uriField); - } - } - - /** - * The configuration for this channel. - * @type {Object} - * @private - */ - this.cfg_ = cfg; - - /** - * The name of the channel. - * @type {string} - * @protected - */ - this.name = this.cfg_[goog.net.xpc.CfgFields.CHANNEL_NAME] || - goog.net.xpc.getRandomString(10); - - /** - * The dom helper to use for accessing the dom. - * @type {goog.dom.DomHelper} - * @private - */ - this.domHelper_ = opt_domHelper || goog.dom.getDomHelper(); - - /** - * Collects deferred function calls which will be made once the connection - * has been fully set up. - * @type {!Array.<function()>} - * @private - */ - this.deferredDeliveries_ = []; - - // If LOCAL_POLL_URI or PEER_POLL_URI is not available, try using - // robots.txt from that host. - cfg[goog.net.xpc.CfgFields.LOCAL_POLL_URI] = - cfg[goog.net.xpc.CfgFields.LOCAL_POLL_URI] || - goog.uri.utils.getHost(this.domHelper_.getWindow().location.href) + - '/robots.txt'; - // PEER_URI is sometimes undefined in tests. - cfg[goog.net.xpc.CfgFields.PEER_POLL_URI] = - cfg[goog.net.xpc.CfgFields.PEER_POLL_URI] || - goog.uri.utils.getHost(cfg[goog.net.xpc.CfgFields.PEER_URI] || '') + - '/robots.txt'; - - goog.net.xpc.channels_[this.name] = this; - - goog.events.listen(window, 'unload', - goog.net.xpc.CrossPageChannel.disposeAll_); - - goog.net.xpc.logger.info('CrossPageChannel created: ' + this.name); -}; -goog.inherits(goog.net.xpc.CrossPageChannel, goog.messaging.AbstractChannel); - - -/** - * Regexp for escaping service names. - * @type {RegExp} - * @private - */ -goog.net.xpc.CrossPageChannel.TRANSPORT_SERVICE_ESCAPE_RE_ = - new RegExp('^%*' + goog.net.xpc.TRANSPORT_SERVICE_ + '$'); - - -/** - * Regexp for unescaping service names. - * @type {RegExp} - * @private - */ -goog.net.xpc.CrossPageChannel.TRANSPORT_SERVICE_UNESCAPE_RE_ = - new RegExp('^%+' + goog.net.xpc.TRANSPORT_SERVICE_ + '$'); - - -/** - * The transport. - * @type {goog.net.xpc.Transport?} - * @private - */ -goog.net.xpc.CrossPageChannel.prototype.transport_ = null; - - -/** - * The channel state. - * @type {number} - * @private - */ -goog.net.xpc.CrossPageChannel.prototype.state_ = - goog.net.xpc.ChannelStates.NOT_CONNECTED; - - -/** - * @override - * @return {boolean} Whether the channel is connected. - */ -goog.net.xpc.CrossPageChannel.prototype.isConnected = function() { - return this.state_ == goog.net.xpc.ChannelStates.CONNECTED; -}; - - -/** - * Reference to the window-object of the peer page. - * @type {Object} - * @private - */ -goog.net.xpc.CrossPageChannel.prototype.peerWindowObject_ = null; - - -/** - * Reference to the iframe-element. - * @type {Object} - * @private - */ -goog.net.xpc.CrossPageChannel.prototype.iframeElement_ = null; - - -/** - * Sets the window object the foreign document resides in. - * - * @param {Object} peerWindowObject The window object of the peer. - */ -goog.net.xpc.CrossPageChannel.prototype.setPeerWindowObject = - function(peerWindowObject) { - this.peerWindowObject_ = peerWindowObject; -}; - - -/** - * Determine which transport type to use for this channel / useragent. - * @return {goog.net.xpc.TransportTypes|undefined} The best transport type. - * @private - */ -goog.net.xpc.CrossPageChannel.prototype.determineTransportType_ = function() { - var transportType; - if (goog.isFunction(document.postMessage) || - goog.isFunction(window.postMessage) || - // IE8 supports window.postMessage, but - // typeof window.postMessage returns "object" - (goog.userAgent.IE && window.postMessage)) { - transportType = goog.net.xpc.TransportTypes.NATIVE_MESSAGING; - } else if (goog.userAgent.GECKO) { - transportType = goog.net.xpc.TransportTypes.FRAME_ELEMENT_METHOD; - } else if (goog.userAgent.IE && - this.cfg_[goog.net.xpc.CfgFields.PEER_RELAY_URI]) { - transportType = goog.net.xpc.TransportTypes.IFRAME_RELAY; - } else if (goog.userAgent.IE && goog.net.xpc.NixTransport.isNixSupported()) { - transportType = goog.net.xpc.TransportTypes.NIX; - } else { - transportType = goog.net.xpc.TransportTypes.IFRAME_POLLING; - } - return transportType; -}; - - -/** - * Creates the transport for this channel. Chooses from the available - * transport based on the user agent and the configuration. - * @private - */ -goog.net.xpc.CrossPageChannel.prototype.createTransport_ = function() { - // return, if the transport has already been created - if (this.transport_) { - return; - } - - if (!this.cfg_[goog.net.xpc.CfgFields.TRANSPORT]) { - this.cfg_[goog.net.xpc.CfgFields.TRANSPORT] = - this.determineTransportType_(); - } - - switch (this.cfg_[goog.net.xpc.CfgFields.TRANSPORT]) { - case goog.net.xpc.TransportTypes.NATIVE_MESSAGING: - this.transport_ = new goog.net.xpc.NativeMessagingTransport( - this, - this.cfg_[goog.net.xpc.CfgFields.PEER_HOSTNAME], - this.domHelper_); - break; - case goog.net.xpc.TransportTypes.NIX: - this.transport_ = new goog.net.xpc.NixTransport(this, this.domHelper_); - break; - case goog.net.xpc.TransportTypes.FRAME_ELEMENT_METHOD: - this.transport_ = - new goog.net.xpc.FrameElementMethodTransport(this, this.domHelper_); - break; - case goog.net.xpc.TransportTypes.IFRAME_RELAY: - this.transport_ = - new goog.net.xpc.IframeRelayTransport(this, this.domHelper_); - break; - case goog.net.xpc.TransportTypes.IFRAME_POLLING: - this.transport_ = - new goog.net.xpc.IframePollingTransport(this, this.domHelper_); - break; - } - - if (this.transport_) { - goog.net.xpc.logger.info('Transport created: ' + this.transport_.getName()); - } else { - throw Error('CrossPageChannel: No suitable transport found!'); - } -}; - - -/** - * Returns the transport type in use for this channel. - * @return {number} Transport-type identifier. - */ -goog.net.xpc.CrossPageChannel.prototype.getTransportType = function() { - return this.transport_.getType(); -}; - - -/** - * Returns the tranport name in use for this channel. - * @return {string} The transport name. - */ -goog.net.xpc.CrossPageChannel.prototype.getTransportName = function() { - return this.transport_.getName(); -}; - - -/** - * @return {Object} Configuration-object to be used by the peer to - * initialize the channel. - */ -goog.net.xpc.CrossPageChannel.prototype.getPeerConfiguration = function() { - var peerCfg = {}; - peerCfg[goog.net.xpc.CfgFields.CHANNEL_NAME] = this.name; - peerCfg[goog.net.xpc.CfgFields.TRANSPORT] = - this.cfg_[goog.net.xpc.CfgFields.TRANSPORT]; - - if (this.cfg_[goog.net.xpc.CfgFields.LOCAL_RELAY_URI]) { - peerCfg[goog.net.xpc.CfgFields.PEER_RELAY_URI] = - this.cfg_[goog.net.xpc.CfgFields.LOCAL_RELAY_URI]; - } - if (this.cfg_[goog.net.xpc.CfgFields.LOCAL_POLL_URI]) { - peerCfg[goog.net.xpc.CfgFields.PEER_POLL_URI] = - this.cfg_[goog.net.xpc.CfgFields.LOCAL_POLL_URI]; - } - if (this.cfg_[goog.net.xpc.CfgFields.PEER_POLL_URI]) { - peerCfg[goog.net.xpc.CfgFields.LOCAL_POLL_URI] = - this.cfg_[goog.net.xpc.CfgFields.PEER_POLL_URI]; - } - - return peerCfg; -}; - - -/** - * Creates the iframe containing the peer page in a specified parent element. - * This method does not connect the channel, connect() still has to be called - * separately. - * - * @param {!Element} parentElm The container element the iframe is appended to. - * @param {Function=} opt_configureIframeCb If present, this function gets - * called with the iframe element as parameter to allow setting properties - * on it before it gets added to the DOM. If absent, the iframe's width and - * height are set to '100%'. - * @param {boolean=} opt_addCfgParam Whether to add the peer configuration as - * URL parameter (default: true). - * @return {!HTMLIFrameElement} The iframe element. - */ -goog.net.xpc.CrossPageChannel.prototype.createPeerIframe = function( - parentElm, opt_configureIframeCb, opt_addCfgParam) { - - var iframeId = this.cfg_[goog.net.xpc.CfgFields.IFRAME_ID]; - if (!iframeId) { - // Create a randomized ID for the iframe element to avoid - // bfcache-related issues. - iframeId = this.cfg_[goog.net.xpc.CfgFields.IFRAME_ID] = - 'xpcpeer' + goog.net.xpc.getRandomString(4); - } - - // TODO(user) Opera creates a history-entry when creating an iframe - // programmatically as follows. Find a way which avoids this. - - var iframeElm = goog.dom.createElement('IFRAME'); - iframeElm.id = iframeElm.name = iframeId; - if (opt_configureIframeCb) { - opt_configureIframeCb(iframeElm); - } else { - iframeElm.style.width = iframeElm.style.height = '100%'; - } - - var peerUri = this.getPeerUri(opt_addCfgParam); - - if (goog.userAgent.GECKO || goog.userAgent.WEBKIT) { - // Appending the iframe in a timeout to avoid a weird fastback issue, which - // is present in Safari and Gecko. - this.deferConnect_ = true; - window.setTimeout( - goog.bind(function() { - this.deferConnect_ = false; - parentElm.appendChild(iframeElm); - iframeElm.src = peerUri.toString(); - goog.net.xpc.logger.info('peer iframe created (' + iframeId + ')'); - if (this.connectDeferred_) { - this.connect(this.connectCb_); - } - }, this), 1); - } else { - iframeElm.src = peerUri.toString(); - parentElm.appendChild(iframeElm); - goog.net.xpc.logger.info('peer iframe created (' + iframeId + ')'); - } - - return /** @type {!HTMLIFrameElement} */ (iframeElm); -}; - - -/** - * Returns the peer URI, with an optional URL parameter for configuring the peer - * window. - * - * @param {boolean=} opt_addCfgParam Whether to add the peer configuration as - * URL parameter (default: true). - * @return {!goog.Uri} The peer URI. - */ -goog.net.xpc.CrossPageChannel.prototype.getPeerUri = function(opt_addCfgParam) { - var peerUri = this.cfg_[goog.net.xpc.CfgFields.PEER_URI]; - if (goog.isString(peerUri)) { - peerUri = this.cfg_[goog.net.xpc.CfgFields.PEER_URI] = - new goog.Uri(peerUri); - } - - // Add the channel configuration used by the peer as URL parameter. - if (opt_addCfgParam !== false) { - peerUri.setParameterValue('xpc', - goog.json.serialize( - this.getPeerConfiguration())); - } - - return peerUri; -}; - - -/** - * Flag whether connecting should be deferred. - * @type {boolean} - * @private - */ -goog.net.xpc.CrossPageChannel.prototype.deferConnect_ = false; - - -/** - * Flag to remember if connect() has been called. - * @type {boolean} - * @private - */ -goog.net.xpc.CrossPageChannel.prototype.connectDeferred_ = false; - - -/** - * Initiates connecting the channel. When this method is called, all the - * information needed to connect the channel has to be available. - * - * @override - * @param {Function=} opt_connectCb The function to be called when the - * channel has been connected and is ready to be used. - */ -goog.net.xpc.CrossPageChannel.prototype.connect = function(opt_connectCb) { - this.connectCb_ = opt_connectCb || goog.nullFunction; - - if (this.deferConnect_) { - goog.net.xpc.logger.info('connect() deferred'); - this.connectDeferred_ = true; - return; - } - this.connectDeferred_ = false; - - goog.net.xpc.logger.info('connect()'); - if (this.cfg_[goog.net.xpc.CfgFields.IFRAME_ID]) { - this.iframeElement_ = this.domHelper_.getElement( - this.cfg_[goog.net.xpc.CfgFields.IFRAME_ID]); - } - if (this.iframeElement_) { - var winObj = this.iframeElement_.contentWindow; - // accessing the window using contentWindow doesn't work in safari - if (!winObj) { - winObj = window.frames[this.cfg_[goog.net.xpc.CfgFields.IFRAME_ID]]; - } - this.setPeerWindowObject(winObj); - } - - // if the peer window object has not been set at this point, we assume - // being in an iframe and the channel is meant to be to the containing page - if (!this.peerWindowObject_) { - // throw an error if we are in the top window (== not in an iframe) - if (window == top) { - throw Error( - "CrossPageChannel: Can't connect, peer window-object not set."); - } else { - this.setPeerWindowObject(window.parent); - } - } - - this.createTransport_(); - - this.transport_.connect(); - - // Now we run any deferred deliveries collected while connection was deferred. - while (this.deferredDeliveries_.length > 0) { - this.deferredDeliveries_.shift()(); - } -}; - - -/** - * Closes the channel. - */ -goog.net.xpc.CrossPageChannel.prototype.close = function() { - if (!this.isConnected()) return; - this.state_ = goog.net.xpc.ChannelStates.CLOSED; - this.transport_.dispose(); - this.transport_ = null; - this.connectCb_ = null; - this.connectDeferred_ = false; - this.deferredDeliveries_.length = 0; - goog.net.xpc.logger.info('Channel "' + this.name + '" closed'); -}; - - -/** - * Called by the transport when the channel is connected. - * @private - */ -goog.net.xpc.CrossPageChannel.prototype.notifyConnected_ = function() { - if (this.isConnected()) { - return; - } - this.state_ = goog.net.xpc.ChannelStates.CONNECTED; - goog.net.xpc.logger.info('Channel "' + this.name + '" connected'); - this.connectCb_(); -}; - - -/** - * Called by the transport in case of an unrecoverable failure. - * @private - */ -goog.net.xpc.CrossPageChannel.prototype.notifyTransportError_ = function() { - goog.net.xpc.logger.info('Transport Error'); - this.close(); -}; - - -/** @override */ -goog.net.xpc.CrossPageChannel.prototype.send = function(serviceName, payload) { - if (!this.isConnected()) { - goog.net.xpc.logger.severe('Can\'t send. Channel not connected.'); - return; - } - // Check if the peer is still around. - // NOTE(user): This check is not reliable in IE, where a document in an - // iframe does not get unloaded when removing the iframe element from the DOM. - // TODO(user): Find something that works in IE as well. - // NOTE(user): "!this.peerWindowObject_.closed" evaluates to 'false' in IE9 - // sometimes even though typeof(this.peerWindowObject_.closed) is boolean and - // this.peerWindowObject_.closed evaluates to 'false'. Casting it to a Boolean - // results in sane evaluation. When this happens, it's in the inner iframe - // when querying its parent's 'closed' status. Note that this is a different - // case than mibuerge@'s note above. - if (Boolean(this.peerWindowObject_.closed)) { - goog.net.xpc.logger.severe('Peer has disappeared.'); - this.close(); - return; - } - if (goog.isObject(payload)) { - payload = goog.json.serialize(payload); - } - - // Partially URL-encode the service name because some characters (: and |) are - // used as delimiters for some transports, and we want to allow those - // characters in service names. - this.transport_.send(this.escapeServiceName_(serviceName), payload); -}; - - -/** - * Delivers messages to the appropriate service-handler. - * - * @param {string} serviceName The name of the port. - * @param {string} payload The payload. - * @param {string=} opt_origin An optional origin for the message, where the - * underlying transport makes that available. If this is specified, and - * the PEER_HOSTNAME parameter was provided, they must match or the message - * will be rejected. - * @private - */ -goog.net.xpc.CrossPageChannel.prototype.deliver_ = function( - serviceName, payload, opt_origin) { - - // This covers the very rare (but producable) case where the inner frame - // becomes ready and sends its setup message while the outer frame is - // deferring its connect method waiting for the inner frame to be ready. - // Without it that message can be passed to deliver_, which is unable to - // process it because the channel is not yet fully configured. - if (this.connectDeferred_) { - this.deferredDeliveries_.push( - goog.bind(this.deliver_, this, serviceName, payload, opt_origin)); - return; - } - - // Check whether the origin of the message is as expected. - if (!this.isMessageOriginAcceptable_(opt_origin)) { - goog.net.xpc.logger.warning('Message received from unapproved origin "' + - opt_origin + '" - rejected.'); - return; - } - - if (this.isDisposed()) { - goog.net.xpc.logger.warning('CrossPageChannel::deliver_(): Disposed.'); - } else if (!serviceName || - serviceName == goog.net.xpc.TRANSPORT_SERVICE_) { - this.transport_.transportServiceHandler(payload); - } else { - // only deliver messages if connected - if (this.isConnected()) { - this.deliver(this.unescapeServiceName_(serviceName), payload); - } else { - goog.net.xpc.logger.info('CrossPageChannel::deliver_(): Not connected.'); - } - } -}; - - -/** - * Escape the user-provided service name for sending across the channel. This - * URL-encodes certain special characters so they don't conflict with delimiters - * used by some of the transports, and adds a special prefix if the name - * conflicts with the reserved transport service name. - * - * This is the opposite of {@link #unescapeServiceName_}. - * - * @param {string} name The name of the service to escape. - * @return {string} The escaped service name. - * @private - */ -goog.net.xpc.CrossPageChannel.prototype.escapeServiceName_ = function(name) { - if (goog.net.xpc.CrossPageChannel.TRANSPORT_SERVICE_ESCAPE_RE_.test(name)) { - name = '%' + name; - } - return name.replace(/[%:|]/g, encodeURIComponent); -}; - - -/** - * Unescape the escaped service name that was sent across the channel. This is - * the opposite of {@link #escapeServiceName_}. - * - * @param {string} name The name of the service to unescape. - * @return {string} The unescaped service name. - * @private - */ -goog.net.xpc.CrossPageChannel.prototype.unescapeServiceName_ = function(name) { - name = name.replace(/%[0-9a-f]{2}/gi, decodeURIComponent); - if (goog.net.xpc.CrossPageChannel.TRANSPORT_SERVICE_UNESCAPE_RE_.test(name)) { - return name.substring(1); - } else { - return name; - } -}; - - -/** - * Returns the role of this channel (either inner or outer). - * @return {number} The role of this channel. - */ -goog.net.xpc.CrossPageChannel.prototype.getRole = function() { - return window.parent == this.peerWindowObject_ ? - goog.net.xpc.CrossPageChannelRole.INNER : - goog.net.xpc.CrossPageChannelRole.OUTER; -}; - - -/** - * Returns whether an incoming message with the given origin is acceptable. - * If an incoming request comes with a specified (non-empty) origin, and the - * PEER_HOSTNAME config parameter has also been provided, the two must match, - * or the message is unacceptable. - * @param {string=} opt_origin The origin associated with the incoming message. - * @return {boolean} Whether the message is acceptable. - * @private - */ -goog.net.xpc.CrossPageChannel.prototype.isMessageOriginAcceptable_ = function( - opt_origin) { - var peerHostname = this.cfg_[goog.net.xpc.CfgFields.PEER_HOSTNAME]; - return goog.string.isEmptySafe(opt_origin) || - goog.string.isEmptySafe(peerHostname) || - opt_origin == this.cfg_[goog.net.xpc.CfgFields.PEER_HOSTNAME]; -}; - - -/** @override */ -goog.net.xpc.CrossPageChannel.prototype.disposeInternal = function() { - goog.base(this, 'disposeInternal'); - - this.close(); - - this.peerWindowObject_ = null; - this.iframeElement_ = null; - delete goog.net.xpc.channels_[this.name]; - this.deferredDeliveries_.length = 0; -}; - - -/** - * Disposes all channels. - * @private - */ -goog.net.xpc.CrossPageChannel.disposeAll_ = function() { - for (var name in goog.net.xpc.channels_) { - var ch = goog.net.xpc.channels_[name]; - if (ch) { - ch.dispose(); - } - } -}; diff --git a/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/text-base/crosspagechannel_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/text-base/crosspagechannel_test.html.svn-base deleted file mode 100644 index 7b895b8..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/text-base/crosspagechannel_test.html.svn-base +++ /dev/null @@ -1,420 +0,0 @@ -<!DOCTYPE html> -<!-- ---> -<html> -<!-- -Copyright 2009 The Closure Library Authors. All Rights Reserved. - -Use of this source code is governed by the Apache License, Version 2.0. -See the COPYING file for details. ---> -<head> -<meta http-equiv="X-UA-Compatible" content="IE=edge"> -<title>CrossPageChannel: End-to-End Test</title> -<script src="../../base.js"></script> -<script> - goog.require('goog.Disposable'); - goog.require('goog.Uri'); - goog.require('goog.debug.Logger'); - goog.require('goog.dom'); - goog.require('goog.net.xpc.CrossPageChannel'); - goog.require('goog.object'); - goog.require('goog.testing.AsyncTestCase'); - goog.require('goog.testing.PropertyReplacer'); - goog.require('goog.testing.jsunit'); -</script> -</head> -<body> -<script> - -var IFRAME_LOAD_WAIT_MS = 2000; -var stubs = new goog.testing.PropertyReplacer(); -var asyncTestCase = goog.testing.AsyncTestCase.createAndInstall( - document.title); -var uniqueId = 0; -var driver; - - -function setUpPage() { - asyncTestCase.stepTimeout = 10 * 1000; - - // Show debug log - var debugDiv = goog.dom.getElement('debugDiv'); - var logger = goog.debug.Logger.getLogger('goog.net.xpc'); - logger.setLevel(goog.debug.Logger.Level.ALL); - logger.addHandler(function(logRecord) { - var msgElm = goog.dom.createDom('div'); - msgElm.innerHTML = logRecord.getMessage(); - goog.dom.appendChild(debugDiv, msgElm); - }); -} - - -function setUp() { - driver = new Driver(); -} - - -function tearDown() { - stubs.reset(); - driver.dispose(); -} - - -function testCreateIframeSpecifyId() { - driver.createPeerIframe('new_iframe'); - - asyncTestCase.waitForAsync('iframe load'); - window.setTimeout(function() { - asyncTestCase.continueTesting(); - driver.checkPeerIframe(); - }, IFRAME_LOAD_WAIT_MS); -} - - -function testCreateIframeRandomId() { - driver.createPeerIframe(); - - asyncTestCase.waitForAsync('iframe load'); - window.setTimeout(function() { - asyncTestCase.continueTesting(); - driver.checkPeerIframe(); - }, IFRAME_LOAD_WAIT_MS); -} - - -function testCreateIframeWithDom() { - driver.createPeerIframe(goog.dom.getDomHelper()); - - asyncTestCase.waitForAsync('iframe load'); - window.setTimeout(function() { - asyncTestCase.continueTesting(); - driver.checkPeerIframe(); - }, IFRAME_LOAD_WAIT_MS); -} - - -function testCreateIframeAsynchronousConnect() { - driver.createPeerIframe('new_iframe'); - - asyncTestCase.waitForAsync('iframe load'); - window.setTimeout(function() { - driver.connect(); - }, IFRAME_LOAD_WAIT_MS); -} - - -function testCreateIframeSynchronousConnect() { - driver.createPeerIframe('new_iframe'); - driver.connect(); -} - - -function testExistingIframeConnect() { - driver.createChannel('test_iframe'); - driver.connect(); -} - -function testEscapeServiceName() { - var escape = goog.net.xpc.CrossPageChannel.prototype.escapeServiceName_; - assertEquals('Shouldn\'t escape alphanumeric name', - 'fooBar123', escape('fooBar123')); - assertEquals('Shouldn\'t escape most non-alphanumeric characters', - '`~!@#$^&*()_-=+ []{}\'";,<.>/?\\', - escape('`~!@#$^&*()_-=+ []{}\'";,<.>/?\\')); - assertEquals('Should escape %, |, and :', - 'foo%3ABar%7C123%25', escape('foo:Bar|123%')); - assertEquals('Should escape tp', '%25tp', escape('tp')); - assertEquals('Should escape %tp', '%25%25tp', escape('%tp')); - assertEquals('Should not escape stp', 'stp', escape('stp')); - assertEquals('Should not escape s%tp', 's%25tp', escape('s%tp')); -} - -function testSameDomainCheck_noMessageOrigin() { - var channel = new goog.net.xpc.CrossPageChannel(goog.object.create( - goog.net.xpc.CfgFields.PEER_HOSTNAME, 'http://foo.com')); - assertTrue(channel.isMessageOriginAcceptable_(undefined)); -} - -function testSameDomainCheck_noPeerHostname() { - var channel = new goog.net.xpc.CrossPageChannel({}); - assertTrue(channel.isMessageOriginAcceptable_('http://foo.com')); -} - -function testSameDomainCheck_unconfigured() { - var channel = new goog.net.xpc.CrossPageChannel({}); - assertTrue(channel.isMessageOriginAcceptable_(undefined)); -} - -function testSameDomainCheck_originsMatch() { - var channel = new goog.net.xpc.CrossPageChannel(goog.object.create( - goog.net.xpc.CfgFields.PEER_HOSTNAME, 'http://foo.com')); - assertTrue(channel.isMessageOriginAcceptable_('http://foo.com')); -} - -function testSameDomainCheck_originsMismatch() { - var channel = new goog.net.xpc.CrossPageChannel(goog.object.create( - goog.net.xpc.CfgFields.PEER_HOSTNAME, 'http://foo.com')); - assertFalse(channel.isMessageOriginAcceptable_('http://nasty.com')); -} - -function testUnescapeServiceName() { - var unescape = goog.net.xpc.CrossPageChannel.prototype.unescapeServiceName_; - assertEquals('Shouldn\'t modify alphanumeric name', - 'fooBar123', unescape('fooBar123')); - assertEquals('Shouldn\'t modify most non-alphanumeric characters', - '`~!@#$^&*()_-=+ []{}\'";,<.>/?\\', - unescape('`~!@#$^&*()_-=+ []{}\'";,<.>/?\\')); - assertEquals('Should unescape URL-escapes', - 'foo:Bar|123%', unescape('foo%3ABar%7C123%25')); - assertEquals('Should unescape tp', 'tp', unescape('%25tp')); - assertEquals('Should unescape %tp', '%tp', unescape('%25%25tp')); - assertEquals('Should not escape stp', 'stp', unescape('stp')); - assertEquals('Should not escape s%tp', 's%tp', unescape('s%25tp')); -} - - -/** - * Driver for the tests for CrossPageChannel. - * - * @constructor - * @extends {goog.Disposable} - */ -Driver = function() { - goog.Disposable.call(this); - - /** - * The peer iframe. - * @type {!Element} - * @private - */ - this.iframe_ = null; - - /** - * The ID of the peer iframe. - * @type {string} - * @private - */ - this.iframeId_ = 'test_iframe'; - - /** - * Channel configuration object. - * @type {Object} - * @private - */ - this.cfg_ = null; - - /** - * The channel to use. - * @type {goog.net.xpc.CrossPageChannel} - * @private - */ - this.channel_ = null; -}; -goog.inherits(Driver, goog.Disposable); - - -/** @override */ -Driver.prototype.disposeInternal = function() { - goog.base(this, 'disposeInternal'); - - if (this.channel_) { - this.channel_.dispose(); - } -}; - - -/** - * Returns the child peer's window object. - * @return {Window} Child peer's window. - * @private - */ -Driver.prototype.getInnerPeer_ = function() { - return window.frames[this.iframeId_]; -}; - - -/** - * Creates the channel. - * @param {string=} opt_iframeId If present, the ID of the iframe to use, - * otherwise, tells the channel to generate an iframe ID. - * @param {goog.dom.DomHelper=} opt_domHelper The optional dom helper to use - * for determining which window to use. - */ -Driver.prototype.createChannel = function(opt_iframeId, opt_domHelper) { - var cfg = {}; - if (opt_iframeId) { - this.iframeId_ = opt_iframeId; - cfg[goog.net.xpc.CfgFields.IFRAME_ID] = opt_iframeId; - } - cfg[goog.net.xpc.CfgFields.PEER_URI] = 'testdata/inner_peer.html'; - cfg[goog.net.xpc.CfgFields.CHANNEL_NAME] = 'test_channel' + uniqueId++; - cfg[goog.net.xpc.CfgFields.LOCAL_POLL_URI] = 'does-not-exist.html'; - cfg[goog.net.xpc.CfgFields.PEER_POLL_URI] = 'does-not-exist.html'; - function resolveUri(fieldName) { - cfg[fieldName] = - goog.Uri.resolve(window.location.href, cfg[fieldName]).toString(); - } - resolveUri(goog.net.xpc.CfgFields.PEER_URI); - resolveUri(goog.net.xpc.CfgFields.LOCAL_POLL_URI); - resolveUri(goog.net.xpc.CfgFields.PEER_POLL_URI); - - this.channel_ = new goog.net.xpc.CrossPageChannel(cfg, opt_domHelper); - this.channel_.registerService('msg', goog.bind(this.msgHandler_, this)); - this.cfg_ = cfg; -}; - - -/** - * Creates the peer iframe. - * @param {string=} opt_iframeId If present, the ID of the iframe to create, - * otherwise, generates an iframe ID. - * @param {goog.dom.DomHelper=} opt_domHelper The dom helper to use for - * finding the elements in the iframe. - */ -Driver.prototype.createPeerIframe = function(opt_iframeId, opt_domHelper) { - var expectedIframeId; - - if (opt_iframeId) { - expectedIframeId = opt_iframeId = opt_iframeId + uniqueId++; - } else { - // Have createPeerIframe() generate an ID - stubs.set(goog.net.xpc, 'getRandomString', function(length) { - return '' + length; - }); - expectedIframeId = 'xpcpeer4'; - } - assertNull('element[id=' + expectedIframeId + '] exists', - goog.dom.getElement(expectedIframeId)); - - this.createChannel(opt_iframeId, opt_domHelper); - this.iframe_ = this.channel_.createPeerIframe(document.body); - - assertEquals(expectedIframeId, this.iframe_.id); - this.iframeId_ = expectedIframeId; -}; - - -/** - * Checks if the peer iframe has been created. - */ -Driver.prototype.checkPeerIframe = function() { - assertNotNull(goog.dom.getElement(this.iframeId_)); - var peer = this.getInnerPeer_(); - assertNotNull(peer); - assertNotNull(peer.document); -}; - - -/** - * Starts the connection. The connection happens asynchronously. - */ -Driver.prototype.connect = function() { - // TODO(user): Get tests to pass for all transports - if (!this.isTransportTestable_()) { - asyncTestCase.continueTesting(); - return; - } - - if (this.iframe_) { - // When we create an iframe, we send the config - // and it connects itself. - this.childConnected_(); - } else { - asyncTestCase.waitForAsync('parent and child connect'); - var peer = this.getInnerPeer_(); - peer.instantiateChannel(this.cfg_); - peer.connectChannel(goog.bind(this.childConnected_, this)); - } - - this.channel_.connect(goog.bind(this.parentConnected_, this)); -}; - - -/** - * Determines if the transport type for the channel is testable. - * Some transports are misusing global state or making other - * assumptions that cause connections to fail. - * @return {boolean} Whether the transport is testable. - * @private - */ -Driver.prototype.isTransportTestable_ = function() { - var testable = true; - - var transportType = this.channel_.determineTransportType_(); - switch (transportType) { - case goog.net.xpc.TransportTypes.NATIVE_MESSAGING: - case goog.net.xpc.TransportTypes.IFRAME_RELAY: - case goog.net.xpc.TransportTypes.IFRAME_POLLING: - case goog.net.xpc.TransportTypes.FLASH: - case goog.net.xpc.TransportTypes.NIX: - testable = false; - break; - } - - return testable; -}; - - -/** - * Callback for the parent connection. - * @private - */ -Driver.prototype.parentConnected_ = function() { - var peer = this.getInnerPeer_(); - if (peer.isConnected()) { - asyncTestCase.waitForAsync('child echo'); - } else { - asyncTestCase.waitForAsync('child connect'); - } - - this.channel_.send('echo', 'hello') -}; - - -/** - * Callback for the child connection. - * @private - */ -Driver.prototype.childConnected_ = function() { - if (this.channel_.isConnected()) { - asyncTestCase.waitForAsync('child echo'); - } else { - asyncTestCase.waitForAsync('parent connect'); - } -}; - - -/** - * The handler function for incoming msg requests. - * @param {string} payload The message payload. - * @private - */ -Driver.prototype.msgHandler_ = function(payload) { - assertTrue('parent should be connected', this.channel_.isConnected()); - var peer = this.getInnerPeer_(); - assertTrue('child should be connected', peer.isConnected()); - assertEquals('hello', payload); - - asyncTestCase.continueTesting(); -}; - - -</script> - -<!-- Debug box. --> -<div style="position:absolute; float: right; top: 10px; right: 10px"> -Debug [<a href="#" onclick="document.getElementById('debugDiv').innerHTML = '';">clear</a>]: <br/> -<div id="debugDiv" style="border: 1px #000000 solid; font-size:xx-small"></div> -</div> - -<!-- -Setup inner peer. This must be done in the <body>, so that the inner peer iframe -blocks the onload event in this window until it is fully loaded. The JsUnit -tests will execute after the onload event fires. ---> -<iframe name=test_iframe id=test_iframe src=testdata/inner_peer.html width=300 height=250> -</iframe> - -</body> -</html> diff --git a/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/text-base/crosspagechannelrole.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/text-base/crosspagechannelrole.js.svn-base deleted file mode 100644 index 0d31fe9..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/text-base/crosspagechannelrole.js.svn-base +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2007 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Provides the enum for the role of the CrossPageChannel. - * - */ - -goog.provide('goog.net.xpc.CrossPageChannelRole'); - - -/** - * The role of the peer. - * @enum {number} - */ -goog.net.xpc.CrossPageChannelRole = { - OUTER: 0, - INNER: 1 -}; diff --git a/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/text-base/frameelementmethodtransport.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/text-base/frameelementmethodtransport.js.svn-base deleted file mode 100644 index f99ed6f..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/text-base/frameelementmethodtransport.js.svn-base +++ /dev/null @@ -1,250 +0,0 @@ -// Copyright 2007 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Contains the frame element method transport for cross-domain - * communication. It exploits the fact that FF lets a page in an - * iframe call a method on the iframe-element it is contained in, even if the - * containing page is from a different domain. - * - */ - - -goog.provide('goog.net.xpc.FrameElementMethodTransport'); - -goog.require('goog.net.xpc'); -goog.require('goog.net.xpc.CrossPageChannelRole'); -goog.require('goog.net.xpc.Transport'); - - - -/** - * Frame-element method transport. - * - * Firefox allows a document within an iframe to call methods on the - * iframe-element added by the containing document. - * NOTE(user): Tested in all FF versions starting from 1.0 - * - * @param {goog.net.xpc.CrossPageChannel} channel The channel this transport - * belongs to. - * @param {goog.dom.DomHelper=} opt_domHelper The dom helper to use for finding - * the correct window. - * @constructor - * @extends {goog.net.xpc.Transport} - */ -goog.net.xpc.FrameElementMethodTransport = function(channel, opt_domHelper) { - goog.base(this, opt_domHelper); - - /** - * The channel this transport belongs to. - * @type {goog.net.xpc.CrossPageChannel} - * @private - */ - this.channel_ = channel; - - // To transfer messages, this transport basically uses normal function calls, - // which are synchronous. To avoid endless recursion, the delivery has to - // be artificially made asynchronous. - - /** - * Array for queued messages. - * @type {Array} - * @private - */ - this.queue_ = []; - - /** - * Callback function which wraps deliverQueued_. - * @type {Function} - * @private - */ - this.deliverQueuedCb_ = goog.bind(this.deliverQueued_, this); -}; -goog.inherits(goog.net.xpc.FrameElementMethodTransport, goog.net.xpc.Transport); - - -/** - * The transport type. - * @type {number} - * @protected - */ -goog.net.xpc.FrameElementMethodTransport.prototype.transportType = - goog.net.xpc.TransportTypes.FRAME_ELEMENT_METHOD; - - -/** - * Flag used to enforce asynchronous messaging semantics. - * @type {boolean} - * @private - */ -goog.net.xpc.FrameElementMethodTransport.prototype.recursive_ = false; - - -/** - * Timer used to enforce asynchronous message delivery. - * @type {number} - * @private - */ -goog.net.xpc.FrameElementMethodTransport.prototype.timer_ = 0; - - -/** - * Holds the function to send messages to the peer - * (once it becomes available). - * @type {Function} - * @private - */ -goog.net.xpc.FrameElementMethodTransport.outgoing_ = null; - - -/** - * Connect this transport. - */ -goog.net.xpc.FrameElementMethodTransport.prototype.connect = function() { - if (this.channel_.getRole() == goog.net.xpc.CrossPageChannelRole.OUTER) { - // get shortcut to iframe-element - this.iframeElm_ = this.channel_.iframeElement_; - - // add the gateway function to the iframe-element - // (to be called by the peer) - this.iframeElm_['XPC_toOuter'] = goog.bind(this.incoming_, this); - - // at this point we just have to wait for a notification from the peer... - - } else { - this.attemptSetup_(); - } -}; - - -/** - * Only used from within an iframe. Attempts to attach the method - * to be used for sending messages by the containing document. Has to - * wait until the containing document has finished. Therefore calls - * itself in a timeout if not successful. - * @private - */ -goog.net.xpc.FrameElementMethodTransport.prototype.attemptSetup_ = function() { - var retry = true; - /** @preserveTry */ - try { - if (!this.iframeElm_) { - // throws security exception when called too early - this.iframeElm_ = this.getWindow().frameElement; - } - // check if iframe-element and the gateway-function to the - // outer-frame are present - // TODO(user) Make sure the following code doesn't throw any exceptions - if (this.iframeElm_ && this.iframeElm_['XPC_toOuter']) { - // get a reference to the gateway function - this.outgoing_ = this.iframeElm_['XPC_toOuter']; - // attach the gateway function the other document will use - this.iframeElm_['XPC_toOuter']['XPC_toInner'] = - goog.bind(this.incoming_, this); - // stop retrying - retry = false; - // notify outer frame - this.send(goog.net.xpc.TRANSPORT_SERVICE_, goog.net.xpc.SETUP_ACK_); - // notify channel that the transport is ready - this.channel_.notifyConnected_(); - } - } - catch (e) { - goog.net.xpc.logger.severe( - 'exception caught while attempting setup: ' + e); - } - // retry necessary? - if (retry) { - if (!this.attemptSetupCb_) { - this.attemptSetupCb_ = goog.bind(this.attemptSetup_, this); - } - this.getWindow().setTimeout(this.attemptSetupCb_, 100); - } -}; - - -/** - * Handles transport service messages. - * @param {string} payload The message content. - */ -goog.net.xpc.FrameElementMethodTransport.prototype.transportServiceHandler = - function(payload) { - if (this.channel_.getRole() == goog.net.xpc.CrossPageChannelRole.OUTER && - !this.channel_.isConnected() && payload == goog.net.xpc.SETUP_ACK_) { - // get a reference to the gateway function - this.outgoing_ = this.iframeElm_['XPC_toOuter']['XPC_toInner']; - // notify the channel we're ready - this.channel_.notifyConnected_(); - } else { - throw Error('Got unexpected transport message.'); - } -}; - - -/** - * Process incoming message. - * @param {string} serviceName The name of the service the message is to be - * delivered to. - * @param {string} payload The message to process. - * @private - */ -goog.net.xpc.FrameElementMethodTransport.prototype.incoming_ = - function(serviceName, payload) { - if (!this.recursive_ && this.queue_.length == 0) { - this.channel_.deliver_(serviceName, payload); - } - else { - this.queue_.push({serviceName: serviceName, payload: payload}); - if (this.queue_.length == 1) { - this.timer_ = this.getWindow().setTimeout(this.deliverQueuedCb_, 1); - } - } -}; - - -/** - * Delivers queued messages. - * @private - */ -goog.net.xpc.FrameElementMethodTransport.prototype.deliverQueued_ = - function() { - while (this.queue_.length) { - var msg = this.queue_.shift(); - this.channel_.deliver_(msg.serviceName, msg.payload); - } -}; - - -/** - * Send a message - * @param {string} service The name off the service the message is to be - * delivered to. - * @param {string} payload The message content. - */ -goog.net.xpc.FrameElementMethodTransport.prototype.send = - function(service, payload) { - this.recursive_ = true; - this.outgoing_(service, payload); - this.recursive_ = false; -}; - - -/** @override */ -goog.net.xpc.FrameElementMethodTransport.prototype.disposeInternal = - function() { - goog.net.xpc.FrameElementMethodTransport.superClass_.disposeInternal.call( - this); - this.outgoing_ = null; - this.iframeElm_ = null; -}; diff --git a/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/text-base/iframepollingtransport.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/text-base/iframepollingtransport.js.svn-base deleted file mode 100644 index aaa96ae..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/text-base/iframepollingtransport.js.svn-base +++ /dev/null @@ -1,829 +0,0 @@ -// Copyright 2007 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Contains the iframe polling transport. - */ - - -goog.provide('goog.net.xpc.IframePollingTransport'); -goog.provide('goog.net.xpc.IframePollingTransport.Receiver'); -goog.provide('goog.net.xpc.IframePollingTransport.Sender'); - -goog.require('goog.array'); -goog.require('goog.dom'); -goog.require('goog.net.xpc'); -goog.require('goog.net.xpc.CrossPageChannelRole'); -goog.require('goog.net.xpc.Transport'); -goog.require('goog.userAgent'); - - - -/** - * Iframe polling transport. Uses hidden iframes to transfer data - * in the fragment identifier of the URL. The peer polls the iframe's location - * for changes. - * Unfortunately, in Safari this screws up the history, because Safari doesn't - * allow to call location.replace() on a window containing a document from a - * different domain (last version tested: 2.0.4). - * - * @param {goog.net.xpc.CrossPageChannel} channel The channel this - * transport belongs to. - * @param {goog.dom.DomHelper=} opt_domHelper The dom helper to use for finding - * the correct window. - * @constructor - * @extends {goog.net.xpc.Transport} - */ -goog.net.xpc.IframePollingTransport = function(channel, opt_domHelper) { - goog.base(this, opt_domHelper); - - /** - * The channel this transport belongs to. - * @type {goog.net.xpc.CrossPageChannel} - * @private - */ - this.channel_ = channel; - - /** - * The URI used to send messages. - * @type {string} - * @private - */ - this.sendUri_ = this.channel_.cfg_[goog.net.xpc.CfgFields.PEER_POLL_URI]; - - /** - * The URI which is polled for incoming messages. - * @type {string} - * @private - */ - this.rcvUri_ = this.channel_.cfg_[goog.net.xpc.CfgFields.LOCAL_POLL_URI]; - - /** - * The queue to hold messages which can't be sent immediately. - * @type {Array} - * @private - */ - this.sendQueue_ = []; -}; -goog.inherits(goog.net.xpc.IframePollingTransport, goog.net.xpc.Transport); - - -/** - * The transport type. - * @type {number} - * @protected - */ -goog.net.xpc.IframePollingTransport.prototype.transportType = - goog.net.xpc.TransportTypes.IFRAME_POLLING; - - -/** - * Sequence counter. - * @type {number} - * @private - */ -goog.net.xpc.IframePollingTransport.prototype.sequence_ = 0; - - -/** - * Flag indicating whether we are waiting for an acknoledgement. - * @type {boolean} - * @private - */ -goog.net.xpc.IframePollingTransport.prototype.waitForAck_ = false; - - -/** - * Flag indicating if channel has been initialized. - * @type {boolean} - * @private - */ -goog.net.xpc.IframePollingTransport.prototype.initialized_ = false; - - -/** - * The string used to prefix all iframe names and IDs. - * @type {string} - */ -goog.net.xpc.IframePollingTransport.IFRAME_PREFIX = 'googlexpc'; - - -/** - * Returns the name/ID of the message frame. - * @return {string} Name of message frame. - * @private - */ -goog.net.xpc.IframePollingTransport.prototype.getMsgFrameName_ = function() { - return goog.net.xpc.IframePollingTransport.IFRAME_PREFIX + '_' + - this.channel_.name + '_msg'; -}; - - -/** - * Returns the name/ID of the ack frame. - * @return {string} Name of ack frame. - * @private - */ -goog.net.xpc.IframePollingTransport.prototype.getAckFrameName_ = function() { - return goog.net.xpc.IframePollingTransport.IFRAME_PREFIX + '_' + - this.channel_.name + '_ack'; -}; - - -/** - * Connects this transport. - */ -goog.net.xpc.IframePollingTransport.prototype.connect = function() { - if (this.isDisposed()) { - // We should stop polling for connecting if the transport has been - // disposed (i.e., the channel has been closed), otherwise - // outerPeerReconnect_() may throw exceptions when it refers - // channel_.peerWindowObject_ which is reset to null by channel_.close(). - return; - } - - goog.net.xpc.logger.fine('transport connect called'); - if (!this.initialized_) { - goog.net.xpc.logger.fine('initializing...'); - this.constructSenderFrames_(); - this.initialized_ = true; - } - this.checkForeignFramesReady_(); -}; - - -/** - * Creates the iframes which are used to send messages (and acknowledgements) - * to the peer. Sender iframes contain a document from a different origin and - * therefore their content can't be accessed. - * @private - */ -goog.net.xpc.IframePollingTransport.prototype.constructSenderFrames_ = - function() { - var name = this.getMsgFrameName_(); - this.msgIframeElm_ = this.constructSenderFrame_(name); - this.msgWinObj_ = this.getWindow().frames[name]; - - name = this.getAckFrameName_(); - this.ackIframeElm_ = this.constructSenderFrame_(name); - this.ackWinObj_ = this.getWindow().frames[name]; -}; - - -/** - * Constructs a sending frame the the given id. - * @param {string} id The id. - * @return {Element} The constructed frame. - * @private - */ -goog.net.xpc.IframePollingTransport.prototype.constructSenderFrame_ = - function(id) { - goog.net.xpc.logger.finest('constructing sender frame: ' + id); - var ifr = goog.dom.createElement('iframe'); - var s = ifr.style; - s.position = 'absolute'; - s.top = '-10px'; s.left = '10px'; s.width = '1px'; s.height = '1px'; - ifr.id = ifr.name = id; - ifr.src = this.sendUri_ + '#INITIAL'; - this.getWindow().document.body.appendChild(ifr); - return ifr; -}; - - -/** - * The protocol for reconnecting is for the inner frame to change channel - * names, and then communicate the new channel name to the outer peer. - * The outer peer looks in a predefined location for the channel name - * upate. It is important to use a completely new channel name, as this - * will ensure that all messaging iframes are not in the bfcache. - * Otherwise, Safari may pollute the history when modifying the location - * of bfcached iframes. - * @private - */ -goog.net.xpc.IframePollingTransport.prototype.innerPeerReconnect_ = function() { - goog.net.xpc.logger.finest('innerPeerReconnect called'); - this.channel_.name = goog.net.xpc.getRandomString(10); - goog.net.xpc.logger.finest('switching channels: ' + this.channel_.name); - this.deconstructSenderFrames_(); - this.initialized_ = false; - // Communicate new channel name to outer peer. - this.reconnectFrame_ = this.constructSenderFrame_( - goog.net.xpc.IframePollingTransport.IFRAME_PREFIX + - '_reconnect_' + this.channel_.name); -}; - - -/** - * Scans inner peer for a reconnect message, which will be used to update - * the outer peer's channel name. If a reconnect message is found, the - * sender frames will be cleaned up to make way for the new sender frames. - * Only called by the outer peer. - * @private - */ -goog.net.xpc.IframePollingTransport.prototype.outerPeerReconnect_ = function() { - goog.net.xpc.logger.finest('outerPeerReconnect called'); - var frames = this.channel_.peerWindowObject_.frames; - var length = frames.length; - for (var i = 0; i < length; i++) { - var frameName; - try { - if (frames[i] && frames[i].name) { - frameName = frames[i].name; - } - } catch (e) { - // Do nothing. - } - if (!frameName) { - continue; - } - var message = frameName.split('_'); - if (message.length == 3 && - message[0] == goog.net.xpc.IframePollingTransport.IFRAME_PREFIX && - message[1] == 'reconnect') { - // This is a legitimate reconnect message from the peer. Start using - // the peer provided channel name, and start a connection over from - // scratch. - this.channel_.name = message[2]; - this.deconstructSenderFrames_(); - this.initialized_ = false; - break; - } - } -}; - - -/** - * Cleans up the existing sender frames owned by this peer. Only called by - * the outer peer. - * @private - */ -goog.net.xpc.IframePollingTransport.prototype.deconstructSenderFrames_ = - function() { - goog.net.xpc.logger.finest('deconstructSenderFrames called'); - if (this.msgIframeElm_) { - this.msgIframeElm_.parentNode.removeChild(this.msgIframeElm_); - this.msgIframeElm_ = null; - this.msgWinObj_ = null; - } - if (this.ackIframeElm_) { - this.ackIframeElm_.parentNode.removeChild(this.ackIframeElm_); - this.ackIframeElm_ = null; - this.ackWinObj_ = null; - } -}; - - -/** - * Checks if the frames in the peer's page are ready. These contain a - * document from the own domain and are the ones messages are received through. - * @private - */ -goog.net.xpc.IframePollingTransport.prototype.checkForeignFramesReady_ = - function() { - // check if the connected iframe ready - if (!(this.isRcvFrameReady_(this.getMsgFrameName_()) && - this.isRcvFrameReady_(this.getAckFrameName_()))) { - goog.net.xpc.logger.finest('foreign frames not (yet) present'); - - if (this.channel_.getRole() == goog.net.xpc.CrossPageChannelRole.INNER && - !this.reconnectFrame_) { - // The inner peer should always have its receiving frames ready. - // It is safe to assume the channel name has fallen out of sync - // (which happens with bfcached frames). Create "reconnect" frames, - // which the outer peer will find, and use to resync the channel names. - this.innerPeerReconnect_(); - } else if (this.channel_.getRole() == - goog.net.xpc.CrossPageChannelRole.OUTER) { - // The inner peer is either not loaded yet, or the receiving - // frames are simply missing. Since we cannot discern the two cases, we - // should scan for a reconnect message from the inner peer. - this.outerPeerReconnect_(); - } - - // start a timer to check again - this.getWindow().setTimeout(goog.bind(this.connect, this), 100); - } else { - goog.net.xpc.logger.fine('foreign frames present'); - - // Create receivers. - this.msgReceiver_ = new goog.net.xpc.IframePollingTransport.Receiver( - this, - this.channel_.peerWindowObject_.frames[this.getMsgFrameName_()], - goog.bind(this.processIncomingMsg, this)); - this.ackReceiver_ = new goog.net.xpc.IframePollingTransport.Receiver( - this, - this.channel_.peerWindowObject_.frames[this.getAckFrameName_()], - goog.bind(this.processIncomingAck, this)); - - this.checkLocalFramesPresent_(); - } -}; - - -/** - * Checks if the receiving frame is ready. - * @param {string} frameName Which receiving frame to check. - * @return {boolean} Whether the receiving frame is ready. - * @private - */ -goog.net.xpc.IframePollingTransport.prototype.isRcvFrameReady_ = - function(frameName) { - goog.net.xpc.logger.finest('checking for receive frame: ' + frameName); - /** @preserveTry */ - try { - var winObj = this.channel_.peerWindowObject_.frames[frameName]; - if (!winObj || winObj.location.href.indexOf(this.rcvUri_) != 0) { - return false; - } - } catch (e) { - return false; - } - return true; -}; - - -/** - * Checks if the iframes created in the own document are ready. - * @private - */ -goog.net.xpc.IframePollingTransport.prototype.checkLocalFramesPresent_ = - function() { - - // Are the sender frames ready? - // These contain a document from the peer's domain, therefore we can only - // check if the frame itself is present. - var frames = this.channel_.peerWindowObject_.frames; - if (!(frames[this.getAckFrameName_()] && - frames[this.getMsgFrameName_()])) { - // start a timer to check again - if (!this.checkLocalFramesPresentCb_) { - this.checkLocalFramesPresentCb_ = goog.bind( - this.checkLocalFramesPresent_, this); - } - this.getWindow().setTimeout(this.checkLocalFramesPresentCb_, 100); - goog.net.xpc.logger.fine('local frames not (yet) present'); - } else { - // Create senders. - this.msgSender_ = new goog.net.xpc.IframePollingTransport.Sender( - this.sendUri_, this.msgWinObj_); - this.ackSender_ = new goog.net.xpc.IframePollingTransport.Sender( - this.sendUri_, this.ackWinObj_); - - goog.net.xpc.logger.fine('local frames ready'); - - this.getWindow().setTimeout(goog.bind(function() { - this.msgSender_.send(goog.net.xpc.SETUP); - this.sentConnectionSetup_ = true; - this.waitForAck_ = true; - goog.net.xpc.logger.fine('SETUP sent'); - }, this), 100); - } -}; - - -/** - * Check if connection is ready. - * @private - */ -goog.net.xpc.IframePollingTransport.prototype.checkIfConnected_ = function() { - if (this.sentConnectionSetupAck_ && this.rcvdConnectionSetupAck_) { - this.channel_.notifyConnected_(); - - if (this.deliveryQueue_) { - goog.net.xpc.logger.fine('delivering queued messages ' + - '(' + this.deliveryQueue_.length + ')'); - - for (var i = 0, m; i < this.deliveryQueue_.length; i++) { - m = this.deliveryQueue_[i]; - this.channel_.deliver_(m.service, m.payload); - } - delete this.deliveryQueue_; - } - } else { - goog.net.xpc.logger.finest('checking if connected: ' + - 'ack sent:' + this.sentConnectionSetupAck_ + - ', ack rcvd: ' + this.rcvdConnectionSetupAck_); - } -}; - - -/** - * Processes an incoming message. - * @param {string} raw The complete received string. - */ -goog.net.xpc.IframePollingTransport.prototype.processIncomingMsg = - function(raw) { - goog.net.xpc.logger.finest('msg received: ' + raw); - - if (raw == goog.net.xpc.SETUP) { - if (!this.ackSender_) { - // Got SETUP msg, but we can't send an ack. - return; - } - - this.ackSender_.send(goog.net.xpc.SETUP_ACK_); - goog.net.xpc.logger.finest('SETUP_ACK sent'); - - this.sentConnectionSetupAck_ = true; - this.checkIfConnected_(); - - } else if (this.channel_.isConnected() || this.sentConnectionSetupAck_) { - - var pos = raw.indexOf('|'); - var head = raw.substring(0, pos); - var frame = raw.substring(pos + 1); - - // check if it is a framed message - pos = head.indexOf(','); - if (pos == -1) { - var seq = head; - // send acknowledgement - this.ackSender_.send('ACK:' + seq); - this.deliverPayload_(frame); - } else { - var seq = head.substring(0, pos); - // send acknowledgement - this.ackSender_.send('ACK:' + seq); - - var partInfo = head.substring(pos + 1).split('/'); - var part0 = parseInt(partInfo[0], 10); - var part1 = parseInt(partInfo[1], 10); - // create an array to accumulate the parts if this is the - // first frame of a message - if (part0 == 1) { - this.parts_ = []; - } - this.parts_.push(frame); - // deliver the message if this was the last frame of a message - if (part0 == part1) { - this.deliverPayload_(this.parts_.join('')); - delete this.parts_; - } - } - } else { - goog.net.xpc.logger.warning('received msg, but channel is not connected'); - } -}; - - -/** - * Process an incoming acknowdedgement. - * @param {string} msgStr The incoming ack string to process. - */ -goog.net.xpc.IframePollingTransport.prototype.processIncomingAck = - function(msgStr) { - goog.net.xpc.logger.finest('ack received: ' + msgStr); - - if (msgStr == goog.net.xpc.SETUP_ACK_) { - this.waitForAck_ = false; - this.rcvdConnectionSetupAck_ = true; - // send the next frame - this.checkIfConnected_(); - - } else if (this.channel_.isConnected()) { - if (!this.waitForAck_) { - goog.net.xpc.logger.warning('got unexpected ack'); - return; - } - - var seq = parseInt(msgStr.split(':')[1], 10); - if (seq == this.sequence_) { - this.waitForAck_ = false; - this.sendNextFrame_(); - } else { - goog.net.xpc.logger.warning('got ack with wrong sequence'); - } - } else { - goog.net.xpc.logger.warning('received ack, but channel not connected'); - } -}; - - -/** - * Sends a frame (message part). - * @private - */ -goog.net.xpc.IframePollingTransport.prototype.sendNextFrame_ = function() { - // do nothing if we are waiting for an acknowledgement or the - // queue is emtpy - if (this.waitForAck_ || !this.sendQueue_.length) { - return; - } - - var s = this.sendQueue_.shift(); - ++this.sequence_; - this.msgSender_.send(this.sequence_ + s); - goog.net.xpc.logger.finest('msg sent: ' + this.sequence_ + s); - - - this.waitForAck_ = true; -}; - - -/** - * Delivers a message. - * @param {string} s The complete message string ("<service_name>:<payload>"). - * @private - */ -goog.net.xpc.IframePollingTransport.prototype.deliverPayload_ = function(s) { - // determine the service name and the payload - var pos = s.indexOf(':'); - var service = s.substr(0, pos); - var payload = s.substring(pos + 1); - - // deliver the message - if (!this.channel_.isConnected()) { - // as valid messages can come in before a SETUP_ACK has - // been received (because subchannels for msgs and acks are independent), - // delay delivery of early messages until after 'connect'-event - (this.deliveryQueue_ || (this.deliveryQueue_ = [])). - push({service: service, payload: payload}); - goog.net.xpc.logger.finest('queued delivery'); - } else { - this.channel_.deliver_(service, payload); - } -}; - - -// ---- send message ---- - - -/** - * Maximal frame length. - * @type {number} - * @private - */ -goog.net.xpc.IframePollingTransport.prototype.MAX_FRAME_LENGTH_ = 3800; - - -/** - * Sends a message. Splits it in multiple frames if too long (exceeds IE's - * URL-length maximum. - * Wireformat: <seq>[,<frame_no>/<#frames>]|<frame_content> - * - * @param {string} service Name of service this the message has to be delivered. - * @param {string} payload The message content. - */ -goog.net.xpc.IframePollingTransport.prototype.send = - function(service, payload) { - var frame = service + ':' + payload; - // put in queue - if (!goog.userAgent.IE || payload.length <= this.MAX_FRAME_LENGTH_) { - this.sendQueue_.push('|' + frame); - } - else { - var l = payload.length; - var num = Math.ceil(l / this.MAX_FRAME_LENGTH_); // number of frames - var pos = 0; - var i = 1; - while (pos < l) { - this.sendQueue_.push(',' + i + '/' + num + '|' + - frame.substr(pos, this.MAX_FRAME_LENGTH_)); - i++; - pos += this.MAX_FRAME_LENGTH_; - } - } - this.sendNextFrame_(); -}; - - -/** @override */ -goog.net.xpc.IframePollingTransport.prototype.disposeInternal = function() { - goog.base(this, 'disposeInternal'); - - var receivers = goog.net.xpc.IframePollingTransport.receivers_; - goog.array.remove(receivers, this.msgReceiver_); - goog.array.remove(receivers, this.ackReceiver_); - this.msgReceiver_ = this.ackReceiver_ = null; - - goog.dom.removeNode(this.msgIframeElm_); - goog.dom.removeNode(this.ackIframeElm_); - this.msgIframeElm_ = this.ackIframeElm_ = null; - this.msgWinObj_ = this.ackWinObj_ = null; -}; - - -/** - * Array holding all Receiver-instances. - * @type {Array.<goog.net.xpc.IframePollingTransport.Receiver>} - * @private - */ -goog.net.xpc.IframePollingTransport.receivers_ = []; - - -/** - * Short polling interval. - * @type {number} - * @private - */ -goog.net.xpc.IframePollingTransport.TIME_POLL_SHORT_ = 10; - - -/** - * Long polling interval. - * @type {number} - * @private - */ -goog.net.xpc.IframePollingTransport.TIME_POLL_LONG_ = 100; - - -/** - * Period how long to use TIME_POLL_SHORT_ before raising polling-interval - * to TIME_POLL_LONG_ after an activity. - * @type {number} - * @private - */ -goog.net.xpc.IframePollingTransport.TIME_SHORT_POLL_AFTER_ACTIVITY_ = - 1000; - - -/** - * Polls all receivers. - * @private - */ -goog.net.xpc.IframePollingTransport.receive_ = function() { - var rcvd = false; - /** @preserveTry */ - try { - for (var i = 0, l = goog.net.xpc.IframePollingTransport.receivers_.length; - i < l; i++) { - rcvd = rcvd || - goog.net.xpc.IframePollingTransport.receivers_[i].receive(); - } - } catch (e) { - goog.net.xpc.logger.info('receive_() failed: ' + e); - // Notify the channel that the transport had an error. - goog.net.xpc.IframePollingTransport.receivers_[i]. - transport_.channel_.notifyTransportError_(); - // notifyTransportError_() closes the channel and dispoases the transport. - // If there are no other channels present, this.receivers_ will now be empty - // and there is not need to keep polling. - if (!goog.net.xpc.IframePollingTransport.receivers_.length) { - return; - } - } - - var now = goog.now(); - if (rcvd) { - goog.net.xpc.IframePollingTransport.lastActivity_ = now; - } - - // Schedule next check. - var t = now - goog.net.xpc.IframePollingTransport.lastActivity_ < - goog.net.xpc.IframePollingTransport.TIME_SHORT_POLL_AFTER_ACTIVITY_ ? - goog.net.xpc.IframePollingTransport.TIME_POLL_SHORT_ : - goog.net.xpc.IframePollingTransport.TIME_POLL_LONG_; - goog.net.xpc.IframePollingTransport.rcvTimer_ = window.setTimeout( - goog.net.xpc.IframePollingTransport.receiveCb_, t); -}; - - -/** - * Callback that wraps receive_ to be used in timers. - * @type {Function} - * @private - */ -goog.net.xpc.IframePollingTransport.receiveCb_ = goog.bind( - goog.net.xpc.IframePollingTransport.receive_, - goog.net.xpc.IframePollingTransport); - - -/** - * Starts the polling loop. - * @private - */ -goog.net.xpc.IframePollingTransport.startRcvTimer_ = function() { - goog.net.xpc.logger.fine('starting receive-timer'); - goog.net.xpc.IframePollingTransport.lastActivity_ = goog.now(); - if (goog.net.xpc.IframePollingTransport.rcvTimer_) { - window.clearTimeout(goog.net.xpc.IframePollingTransport.rcvTimer_); - } - goog.net.xpc.IframePollingTransport.rcvTimer_ = window.setTimeout( - goog.net.xpc.IframePollingTransport.receiveCb_, - goog.net.xpc.IframePollingTransport.TIME_POLL_SHORT_); -}; - - - -/** - * goog.net.xpc.IframePollingTransport.Sender - * - * Utility class to send message-parts to a document from a different origin. - * - * @constructor - * @param {string} url The url the other document will use for polling. - * @param {Object} windowObj The frame used for sending information to. - */ -goog.net.xpc.IframePollingTransport.Sender = function(url, windowObj) { - /** - * The URI used to sending messages. - * @type {string} - * @private - */ - this.sendUri_ = url; - - /** - * The window object of the iframe used to send messages. - * The script instantiating the Sender won't have access to - * the content of sendFrame_. - * @type {Object} - * @private - */ - this.sendFrame_ = windowObj; - - /** - * Cycle counter (used to make sure that sending two identical messages sent - * in direct succession can be recognized as such by the receiver). - * @type {number} - * @private - */ - this.cycle_ = 0; -}; - - -/** - * Sends a message-part (frame) to the peer. - * The message-part is encoded and put in the fragment identifier - * of the URL used for sending (and belongs to the origin/domain of the peer). - * @param {string} payload The message to send. - */ -goog.net.xpc.IframePollingTransport.Sender.prototype.send = function(payload) { - this.cycle_ = ++this.cycle_ % 2; - - var url = this.sendUri_ + '#' + this.cycle_ + encodeURIComponent(payload); - - // TODO(user) Find out if try/catch is still needed - /** @preserveTry */ - try { - // safari doesn't allow to call location.replace() - if (goog.userAgent.WEBKIT) { - this.sendFrame_.location.href = url; - } else { - this.sendFrame_.location.replace(url); - } - } catch (e) { - goog.net.xpc.logger.severe('sending failed', e); - } - - // Restart receiver timer on short polling interval, to support use-cases - // where we need to capture responses quickly. - goog.net.xpc.IframePollingTransport.startRcvTimer_(); -}; - - - -/** - * goog.net.xpc.IframePollingTransport.Receiver - * - * @constructor - * @param {goog.net.xpc.Transport} transport The transport to receive from. - * @param {Object} windowObj The window-object to poll for location-changes. - * @param {Function} callback The callback-function to be called when - * location has changed. - */ -goog.net.xpc.IframePollingTransport.Receiver = function(transport, - windowObj, - callback) { - - this.transport_ = transport; - this.rcvFrame_ = windowObj; - - this.cb_ = callback; - - this.currentLoc_ = this.rcvFrame_.location.href.split('#')[0] + '#INITIAL'; - - goog.net.xpc.IframePollingTransport.receivers_.push(this); - goog.net.xpc.IframePollingTransport.startRcvTimer_(); -}; - - -/** - * Polls the location of the receiver-frame for changes. - * @return {boolean} Whether a change has been detected. - */ -goog.net.xpc.IframePollingTransport.Receiver.prototype.receive = function() { - var loc = this.rcvFrame_.location.href; - - if (loc != this.currentLoc_) { - this.currentLoc_ = loc; - var payload = loc.split('#')[1]; - if (payload) { - payload = payload.substr(1); // discard first character (cycle) - this.cb_(decodeURIComponent(payload)); - } - return true; - } else { - return false; - } -}; diff --git a/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/text-base/iframerelaytransport.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/text-base/iframerelaytransport.js.svn-base deleted file mode 100644 index 2f49ad5..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/text-base/iframerelaytransport.js.svn-base +++ /dev/null @@ -1,388 +0,0 @@ -// Copyright 2007 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Contains the iframe relay tranport. - */ - - -goog.provide('goog.net.xpc.IframeRelayTransport'); - -goog.require('goog.dom'); -goog.require('goog.events'); -goog.require('goog.net.xpc'); -goog.require('goog.net.xpc.Transport'); -goog.require('goog.userAgent'); - - - -/** - * Iframe relay transport. Creates hidden iframes containing a document - * from the peer's origin. Data is transferred in the fragment identifier. - * Therefore the document loaded in the iframes can be served from the - * browser's cache. - * - * @param {goog.net.xpc.CrossPageChannel} channel The channel this - * transport belongs to. - * @param {goog.dom.DomHelper=} opt_domHelper The dom helper to use for finding - * the correct window. - * @constructor - * @extends {goog.net.xpc.Transport} - */ -goog.net.xpc.IframeRelayTransport = function(channel, opt_domHelper) { - goog.base(this, opt_domHelper); - - /** - * The channel this transport belongs to. - * @type {goog.net.xpc.CrossPageChannel} - * @private - */ - this.channel_ = channel; - - /** - * The URI used to relay data to the peer. - * @type {string} - * @private - */ - this.peerRelayUri_ = - this.channel_.cfg_[goog.net.xpc.CfgFields.PEER_RELAY_URI]; - - /** - * The id of the iframe the peer page lives in. - * @type {string} - * @private - */ - this.peerIframeId_ = this.channel_.cfg_[goog.net.xpc.CfgFields.IFRAME_ID]; - - if (goog.userAgent.WEBKIT) { - goog.net.xpc.IframeRelayTransport.startCleanupTimer_(); - } -}; -goog.inherits(goog.net.xpc.IframeRelayTransport, goog.net.xpc.Transport); - - -if (goog.userAgent.WEBKIT) { - /** - * Array to keep references to the relay-iframes. Used only if - * there is no way to detect when the iframes are loaded. In that - * case the relay-iframes are removed after a timeout. - * @type {Array.<Object>} - * @private - */ - goog.net.xpc.IframeRelayTransport.iframeRefs_ = []; - - - /** - * Interval at which iframes are destroyed. - * @type {number} - * @private - */ - goog.net.xpc.IframeRelayTransport.CLEANUP_INTERVAL_ = 1000; - - - /** - * Time after which a relay-iframe is destroyed. - * @type {number} - * @private - */ - goog.net.xpc.IframeRelayTransport.IFRAME_MAX_AGE_ = 3000; - - - /** - * The cleanup timer id. - * @type {number} - * @private - */ - goog.net.xpc.IframeRelayTransport.cleanupTimer_ = 0; - - - /** - * Starts the cleanup timer. - * @private - */ - goog.net.xpc.IframeRelayTransport.startCleanupTimer_ = function() { - if (!goog.net.xpc.IframeRelayTransport.cleanupTimer_) { - goog.net.xpc.IframeRelayTransport.cleanupTimer_ = window.setTimeout( - function() { goog.net.xpc.IframeRelayTransport.cleanup_(); }, - goog.net.xpc.IframeRelayTransport.CLEANUP_INTERVAL_); - } - }; - - - /** - * Remove all relay-iframes which are older than the maximal age. - * @param {number=} opt_maxAge The maximal age in milliseconds. - * @private - */ - goog.net.xpc.IframeRelayTransport.cleanup_ = function(opt_maxAge) { - var now = goog.now(); - var maxAge = - opt_maxAge || goog.net.xpc.IframeRelayTransport.IFRAME_MAX_AGE_; - - while (goog.net.xpc.IframeRelayTransport.iframeRefs_.length && - now - goog.net.xpc.IframeRelayTransport.iframeRefs_[0].timestamp >= - maxAge) { - var ifr = goog.net.xpc.IframeRelayTransport.iframeRefs_. - shift().iframeElement; - goog.dom.removeNode(ifr); - goog.net.xpc.logger.finest('iframe removed'); - } - - goog.net.xpc.IframeRelayTransport.cleanupTimer_ = window.setTimeout( - goog.net.xpc.IframeRelayTransport.cleanupCb_, - goog.net.xpc.IframeRelayTransport.CLEANUP_INTERVAL_); - }; - - - /** - * Function which wraps cleanup_(). - * @private - */ - goog.net.xpc.IframeRelayTransport.cleanupCb_ = function() { - goog.net.xpc.IframeRelayTransport.cleanup_(); - }; -} - - -/** - * Maximum sendable size of a payload via a single iframe in IE. - * @type {number} - * @private - */ -goog.net.xpc.IframeRelayTransport.IE_PAYLOAD_MAX_SIZE_ = 1800; - - -/** - * @typedef {{fragments: !Array.<string>, received: number, expected: number}} - */ -goog.net.xpc.IframeRelayTransport.FragmentInfo; - - -/** - * Used to track incoming payload fragments. The implementation can process - * incoming fragments from several channels at a time, even if data is - * out-of-order or interleaved. - * - * @type {!Object.<string, !goog.net.xpc.IframeRelayTransport.FragmentInfo>} - * @private - */ -goog.net.xpc.IframeRelayTransport.fragmentMap_ = {}; - - -/** - * The transport type. - * @type {number} - */ -goog.net.xpc.IframeRelayTransport.prototype.transportType = - goog.net.xpc.TransportTypes.IFRAME_RELAY; - - -/** - * Connects this transport. - */ -goog.net.xpc.IframeRelayTransport.prototype.connect = function() { - if (!this.getWindow()['xpcRelay']) { - this.getWindow()['xpcRelay'] = - goog.net.xpc.IframeRelayTransport.receiveMessage_; - } - - this.send(goog.net.xpc.TRANSPORT_SERVICE_, goog.net.xpc.SETUP); -}; - - -/** - * Processes an incoming message. - * - * @param {string} channelName The name of the channel. - * @param {string} frame The raw frame content. - * @private - */ -goog.net.xpc.IframeRelayTransport.receiveMessage_ = - function(channelName, frame) { - var pos = frame.indexOf(':'); - var header = frame.substr(0, pos); - var payload = frame.substr(pos + 1); - - if (!goog.userAgent.IE || (pos = header.indexOf('|')) == -1) { - // First, the easy case. - var service = header; - } else { - // There was a fragment id in the header, so this is a message - // fragment, not a whole message. - var service = header.substr(0, pos); - var fragmentIdStr = header.substr(pos + 1); - - // Separate the message id string and the fragment number. Note that - // there may be a single leading + in the argument to parseInt, but - // this is harmless. - pos = fragmentIdStr.indexOf('+'); - var messageIdStr = fragmentIdStr.substr(0, pos); - var fragmentNum = parseInt(fragmentIdStr.substr(pos + 1), 10); - var fragmentInfo = - goog.net.xpc.IframeRelayTransport.fragmentMap_[messageIdStr]; - if (!fragmentInfo) { - fragmentInfo = - goog.net.xpc.IframeRelayTransport.fragmentMap_[messageIdStr] = - {fragments: [], received: 0, expected: 0}; - } - - if (goog.string.contains(fragmentIdStr, '++')) { - fragmentInfo.expected = fragmentNum + 1; - } - fragmentInfo.fragments[fragmentNum] = payload; - fragmentInfo.received++; - - if (fragmentInfo.received != fragmentInfo.expected) { - return; - } - - // We've received all outstanding fragments; combine what we've received - // into payload and fall out to the call to deliver_. - payload = fragmentInfo.fragments.join(''); - delete goog.net.xpc.IframeRelayTransport.fragmentMap_[messageIdStr]; - } - - goog.net.xpc.channels_[channelName].deliver_(service, - decodeURIComponent(payload)); -}; - - -/** - * Handles transport service messages (internal signalling). - * @param {string} payload The message content. - */ -goog.net.xpc.IframeRelayTransport.prototype.transportServiceHandler = - function(payload) { - if (payload == goog.net.xpc.SETUP) { - // TODO(user) Safari swallows the SETUP_ACK from the iframe to the - // container after hitting reload. - this.send(goog.net.xpc.TRANSPORT_SERVICE_, goog.net.xpc.SETUP_ACK_); - this.channel_.notifyConnected_(); - } - else if (payload == goog.net.xpc.SETUP_ACK_) { - this.channel_.notifyConnected_(); - } -}; - - -/** - * Sends a message. - * - * @param {string} service Name of service this the message has to be delivered. - * @param {string} payload The message content. - */ -goog.net.xpc.IframeRelayTransport.prototype.send = function(service, payload) { - // If we're on IE and the post-encoding payload is large, split it - // into multiple payloads and send each one separately. Otherwise, - // just send the whole thing. - var encodedPayload = encodeURIComponent(payload); - var encodedLen = encodedPayload.length; - var maxSize = goog.net.xpc.IframeRelayTransport.IE_PAYLOAD_MAX_SIZE_; - - if (goog.userAgent.IE && encodedLen > maxSize) { - // A probabilistically-unique string used to link together all fragments - // in this message. - var messageIdStr = goog.string.getRandomString(); - - for (var startIndex = 0, fragmentNum = 0; startIndex < encodedLen; - fragmentNum++) { - var payloadFragment = encodedPayload.substr(startIndex, maxSize); - startIndex += maxSize; - var fragmentIdStr = - messageIdStr + (startIndex >= encodedLen ? '++' : '+') + fragmentNum; - this.send_(service, payloadFragment, fragmentIdStr); - } - } else { - this.send_(service, encodedPayload); - } -}; - - -/** - * Sends an encoded message or message fragment. - * @param {string} service Name of service this the message has to be delivered. - * @param {string} encodedPayload The message content, URI encoded. - * @param {string=} opt_fragmentIdStr If sending a fragment, a string that - * identifies the fragment. - * @private - */ -goog.net.xpc.IframeRelayTransport.prototype.send_ = - function(service, encodedPayload, opt_fragmentIdStr) { - // IE requires that we create the onload attribute inline, otherwise the - // handler is not triggered - if (goog.userAgent.IE) { - var div = this.getWindow().document.createElement('div'); - div.innerHTML = '<iframe onload="this.xpcOnload()"></iframe>'; - var ifr = div.childNodes[0]; - div = null; - ifr['xpcOnload'] = goog.net.xpc.IframeRelayTransport.iframeLoadHandler_; - } else { - var ifr = this.getWindow().document.createElement('iframe'); - - if (goog.userAgent.WEBKIT) { - // safari doesn't fire load-events on iframes. - // keep a reference and remove after a timeout. - goog.net.xpc.IframeRelayTransport.iframeRefs_.push({ - timestamp: goog.now(), - iframeElement: ifr - }); - } else { - goog.events.listen(ifr, 'load', - goog.net.xpc.IframeRelayTransport.iframeLoadHandler_); - } - } - - var style = ifr.style; - style.visibility = 'hidden'; - style.width = ifr.style.height = '0px'; - style.position = 'absolute'; - - var url = this.peerRelayUri_; - url += '#' + this.channel_.name; - if (this.peerIframeId_) { - url += ',' + this.peerIframeId_; - } - url += '|' + service; - if (opt_fragmentIdStr) { - url += '|' + opt_fragmentIdStr; - } - url += ':' + encodedPayload; - - ifr.src = url; - - this.getWindow().document.body.appendChild(ifr); - - goog.net.xpc.logger.finest('msg sent: ' + url); -}; - - -/** - * The iframe load handler. Gets called as method on the iframe element. - * @private - * @this Element - */ -goog.net.xpc.IframeRelayTransport.iframeLoadHandler_ = function() { - goog.net.xpc.logger.finest('iframe-load'); - goog.dom.removeNode(this); - this.xpcOnload = null; -}; - - -/** @override */ -goog.net.xpc.IframeRelayTransport.prototype.disposeInternal = function() { - goog.base(this, 'disposeInternal'); - if (goog.userAgent.WEBKIT) { - goog.net.xpc.IframeRelayTransport.cleanup_(0); - } -}; diff --git a/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/text-base/nativemessagingtransport.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/text-base/nativemessagingtransport.js.svn-base deleted file mode 100644 index 4458471..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/text-base/nativemessagingtransport.js.svn-base +++ /dev/null @@ -1,287 +0,0 @@ -// Copyright 2007 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Contains the class which uses native messaging - * facilities for cross domain communication. - * - */ - - -goog.provide('goog.net.xpc.NativeMessagingTransport'); - -goog.require('goog.events'); -goog.require('goog.net.xpc'); -goog.require('goog.net.xpc.CrossPageChannelRole'); -goog.require('goog.net.xpc.Transport'); - - - -/** - * The native messaging transport - * - * Uses document.postMessage() to send messages to other documents. - * Receiving is done by listening on 'message'-events on the document. - * - * @param {goog.net.xpc.CrossPageChannel} channel The channel this - * transport belongs to. - * @param {string} peerHostname The hostname (protocol, domain, and port) of the - * peer. - * @param {goog.dom.DomHelper=} opt_domHelper The dom helper to use for - * finding the correct window/document. - * @constructor - * @extends {goog.net.xpc.Transport} - */ -goog.net.xpc.NativeMessagingTransport = function(channel, peerHostname, - opt_domHelper) { - goog.base(this, opt_domHelper); - - /** - * The channel this transport belongs to. - * @type {goog.net.xpc.CrossPageChannel} - * @private - */ - this.channel_ = channel; - - /** - * The hostname of the peer. This parameterizes all calls to postMessage, and - * should contain the precise protocol, domain, and port of the peer window. - * @type {string} - * @private - */ - this.peerHostname_ = peerHostname || '*'; -}; -goog.inherits(goog.net.xpc.NativeMessagingTransport, goog.net.xpc.Transport); - - -/** - * Flag indicating if this instance of the transport has been initialized. - * @type {boolean} - * @private - */ -goog.net.xpc.NativeMessagingTransport.prototype.initialized_ = false; - - -/** - * The transport type. - * @type {number} - */ -goog.net.xpc.NativeMessagingTransport.prototype.transportType = - goog.net.xpc.TransportTypes.NATIVE_MESSAGING; - - -/** - * Tracks the number of NativeMessagingTransport channels that have been - * initialized but not disposed yet in a map keyed by the UID of the window - * object. This allows for multiple windows to be initiallized and listening - * for messages. - * @type {Object.<number>} - * @private - */ -goog.net.xpc.NativeMessagingTransport.activeCount_ = {}; - - -/** - * Initializes this transport. Registers a listener for 'message'-events - * on the document. - * @param {Window} listenWindow The window to listen to events on. - * @private - */ -goog.net.xpc.NativeMessagingTransport.initialize_ = function(listenWindow) { - var uid = goog.getUid(listenWindow); - var value = goog.net.xpc.NativeMessagingTransport.activeCount_[uid]; - if (!goog.isNumber(value)) { - value = 0; - } - if (value == 0) { - // Listen for message-events. These are fired on window in FF3 and on - // document in Opera. - goog.events.listen( - listenWindow.postMessage ? listenWindow : listenWindow.document, - 'message', - goog.net.xpc.NativeMessagingTransport.messageReceived_, - false, - goog.net.xpc.NativeMessagingTransport); - } - goog.net.xpc.NativeMessagingTransport.activeCount_[uid] = value + 1; -}; - - -/** - * Processes an incoming message-event. - * @param {goog.events.BrowserEvent} msgEvt The message event. - * @return {boolean} True if message was successfully delivered to a channel. - * @private - */ -goog.net.xpc.NativeMessagingTransport.messageReceived_ = function(msgEvt) { - var data = msgEvt.getBrowserEvent().data; - - if (!goog.isString(data)) { - return false; - } - - var headDelim = data.indexOf('|'); - var serviceDelim = data.indexOf(':'); - - // make sure we got something reasonable - if (headDelim == -1 || serviceDelim == -1) { - return false; - } - - var channelName = data.substring(0, headDelim); - var service = data.substring(headDelim + 1, serviceDelim); - var payload = data.substring(serviceDelim + 1); - - goog.net.xpc.logger.fine('messageReceived: channel=' + channelName + - ', service=' + service + ', payload=' + payload); - - // Attempt to deliver message to the channel. Keep in mind that it may not - // exist for several reasons, including but not limited to: - // - a malformed message - // - the channel simply has not been created - // - channel was created in a different namespace - // - message was sent to the wrong window - // - channel has become stale (e.g. caching iframes and back clicks) - var channel = goog.net.xpc.channels_[channelName]; - if (channel) { - channel.deliver_(service, payload, msgEvt.getBrowserEvent().origin); - return true; - } - - // Check if there are any stale channel names that can be updated. - for (var staleChannelName in goog.net.xpc.channels_) { - var staleChannel = goog.net.xpc.channels_[staleChannelName]; - if (staleChannel.getRole() == goog.net.xpc.CrossPageChannelRole.INNER && - !staleChannel.isConnected() && - service == goog.net.xpc.TRANSPORT_SERVICE_ && - payload == goog.net.xpc.SETUP) { - // Inner peer received SETUP message but channel names did not match. - // Start using the channel name sent from outer peer. The channel name - // of the inner peer can easily become out of date, as iframe's and their - // JS state get cached in many browsers upon page reload or history - // navigation (particularly Firefox 1.5+). We can trust the outer peer, - // since we only accept postMessage messages from the same hostname that - // originally setup the channel. - goog.net.xpc.logger.fine('changing channel name to ' + channelName); - staleChannel.name = channelName; - // Remove old stale pointer to channel. - delete goog.net.xpc.channels_[staleChannelName]; - // Create fresh pointer to channel. - goog.net.xpc.channels_[channelName] = staleChannel; - staleChannel.deliver_(service, payload); - return true; - } - } - - // Failed to find a channel to deliver this message to, so simply ignore it. - goog.net.xpc.logger.info('channel name mismatch; message ignored"'); - return false; -}; - - -/** - * Handles transport service messages. - * @param {string} payload The message content. - */ -goog.net.xpc.NativeMessagingTransport.prototype.transportServiceHandler = - function(payload) { - switch (payload) { - case goog.net.xpc.SETUP: - this.send(goog.net.xpc.TRANSPORT_SERVICE_, goog.net.xpc.SETUP_ACK_); - break; - case goog.net.xpc.SETUP_ACK_: - this.channel_.notifyConnected_(); - break; - } -}; - - -/** - * Connects this transport. - */ -goog.net.xpc.NativeMessagingTransport.prototype.connect = function() { - goog.net.xpc.NativeMessagingTransport.initialize_(this.getWindow()); - this.initialized_ = true; - this.connectWithRetries_(); -}; - - -/** - * Connects to other peer. In the case of the outer peer, the setup messages are - * likely sent before the inner peer is ready to receive them. Therefore, this - * function will continue trying to send the SETUP message until the inner peer - * responds. In the case of the inner peer, it will occasionally have its - * channel name fall out of sync with the outer peer, particularly during - * soft-reloads and history navigations. - * @private - */ -goog.net.xpc.NativeMessagingTransport.prototype.connectWithRetries_ = - function() { - if (this.channel_.isConnected() || this.isDisposed()) { - return; - } - this.send(goog.net.xpc.TRANSPORT_SERVICE_, goog.net.xpc.SETUP); - this.getWindow().setTimeout(goog.bind(this.connectWithRetries_, this), 100); -}; - - -/** - * Sends a message. - * @param {string} service The name off the service the message is to be - * delivered to. - * @param {string} payload The message content. - */ -goog.net.xpc.NativeMessagingTransport.prototype.send = function(service, - payload) { - var win = this.channel_.peerWindowObject_; - if (!win) { - goog.net.xpc.logger.fine('send(): window not ready'); - return; - } - - // postMessage is a method of the window object, except in some versions of - // Opera, where it is a method of the document object. - var obj = win.postMessage ? win : win.document; - this.send = function(service, payload) { - goog.net.xpc.logger.fine('send(): payload=' + payload + - ' to hostname=' + this.peerHostname_); - obj.postMessage(this.channel_.name + '|' + service + ':' + payload, - this.peerHostname_); - }; - this.send(service, payload); -}; - - -/** @override */ -goog.net.xpc.NativeMessagingTransport.prototype.disposeInternal = function() { - goog.base(this, 'disposeInternal'); - if (this.initialized_) { - var listenWindow = this.getWindow(); - var uid = goog.getUid(listenWindow); - var value = goog.net.xpc.NativeMessagingTransport.activeCount_[uid]; - goog.net.xpc.NativeMessagingTransport.activeCount_[uid] = value - 1; - if (value == 1) { - goog.events.unlisten( - listenWindow.postMessage ? listenWindow : listenWindow.document, - 'message', - goog.net.xpc.NativeMessagingTransport.messageReceived_, - false, - goog.net.xpc.NativeMessagingTransport); - } - } - // Cleaning up this.send as it is an instance method, created in - // goog.net.xpc.NativeMessagingTransport.prototype.send and has a closure over - // this.channel_.peerWindowObject_. - delete this.send; -}; diff --git a/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/text-base/nativemessagingtransport_test.html.svn-base b/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/text-base/nativemessagingtransport_test.html.svn-base deleted file mode 100644 index a18cb2a..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/text-base/nativemessagingtransport_test.html.svn-base +++ /dev/null @@ -1,165 +0,0 @@ -<!-- ---> -<html> -<!-- -Copyright 2008 The Closure Library Authors. All Rights Reserved. - -Use of this source code is governed by the Apache License, Version 2.0. -See the COPYING file for details. ---> -<head> -<meta http-equiv="X-UA-Compatible" content="IE=edge"> -<title>NativeMessagingTransport Unit-Tests</title> -<script src="../../base.js"></script> -<script> - goog.require('goog.net.xpc.CrossPageChannel'); - goog.require('goog.net.xpc.CrossPageChannelRole'); - goog.require('goog.net.xpc.NativeMessagingTransport'); - goog.require('goog.testing.events'); - goog.require('goog.testing.jsunit'); -</script> -<script> - -function tearDown() { - goog.net.xpc.NativeMessagingTransport.activeCount_ = {}; - goog.events.removeAll(window.postMessage ? window : document, 'message'); -} - - -function testConstructor() { - var t = new goog.net.xpc.NativeMessagingTransport(null, 'http://g.com:80'); - assertEquals('http://g.com:80', t.peerHostname_); - - var t = new goog.net.xpc.NativeMessagingTransport(null, null); - assertEquals('*', t.peerHostname_); - t.dispose(); -} - - -function testConstructorDom() { - var t = new goog.net.xpc.NativeMessagingTransport( - null, 'http://g.com:80', goog.dom.getDomHelper()); - assertEquals('http://g.com:80', t.peerHostname_); - - var t = new goog.net.xpc.NativeMessagingTransport(null, null); - assertEquals('*', t.peerHostname_); - t.dispose(); -} - - -function testDispose() { - var xpc = getTestChannel(); - var listenedObj = window.postMessage ? window : document; - - var t0 = new goog.net.xpc.NativeMessagingTransport(xpc, null); - assertEquals(0, goog.events.removeAll(listenedObj, 'message')); - t0.dispose(); - assertEquals(0, goog.events.removeAll(listenedObj, 'message')); - - var t1 = new goog.net.xpc.NativeMessagingTransport(xpc, null); - t1.connect(); - t1.dispose(); - assertEquals(0, goog.events.removeAll(listenedObj, 'message')); - - var t2 = new goog.net.xpc.NativeMessagingTransport(xpc, null); - var t3 = new goog.net.xpc.NativeMessagingTransport(xpc, null); - t2.connect(); - t3.connect(); - t2.dispose(); - assertEquals(1, goog.events.removeAll(listenedObj, 'message')); -} - - -function testDisposeWithDom() { - var xpc = getTestChannel(goog.dom.getDomHelper()); - var listenedObj = window.postMessage ? window : document; - - var t0 = new goog.net.xpc.NativeMessagingTransport(xpc, null); - assertEquals(0, goog.events.removeAll(listenedObj, 'message')); - t0.dispose(); - assertEquals(0, goog.events.removeAll(listenedObj, 'message')); - - var t1 = new goog.net.xpc.NativeMessagingTransport(xpc, null); - t1.connect(); - t1.dispose(); - assertEquals(0, goog.events.removeAll(listenedObj, 'message')); - - var t2 = new goog.net.xpc.NativeMessagingTransport(xpc, null); - var t3 = new goog.net.xpc.NativeMessagingTransport(xpc, null); - t2.connect(); - t3.connect(); - t2.dispose(); - assertEquals(1, goog.events.removeAll(listenedObj, 'message')); -} - - -function testBogusMessages() { - var e = createMockEvent('bogus_message'); - assertFalse(goog.net.xpc.NativeMessagingTransport.messageReceived_(e)); - - e = createMockEvent('bogus|message'); - assertFalse(goog.net.xpc.NativeMessagingTransport.messageReceived_(e)); - - e = createMockEvent('bogus|message:data'); - assertFalse(goog.net.xpc.NativeMessagingTransport.messageReceived_(e)); -} - - -function testSendingMessagesToUnconnectedInnerPeer() { - var xpc = getTestChannel(); - - var serviceResult, payloadResult; - xpc.deliver_ = function(service, payload) { - serviceResult = service; - payloadResult = payload; - }; - - // Construct an unconnected inner peer. - xpc.getRole = function() { - return goog.net.xpc.CrossPageChannelRole.INNER; - }; - xpc.isConnected = function() { - return false; - }; - var t = new goog.net.xpc.NativeMessagingTransport(xpc, 'http://g.com'); - - // Test a valid message. - var e = createMockEvent('test_channel|test_service:test_payload'); - assertTrue(goog.net.xpc.NativeMessagingTransport.messageReceived_(e)); - assertEquals('test_service', serviceResult); - assertEquals('test_payload', payloadResult); - assertEquals('Ensure channel name has not been changed.', - 'test_channel', - t.channel_.name); - - // Test updating a stale inner peer. - var e = createMockEvent('new_channel|tp:SETUP'); - assertTrue(goog.net.xpc.NativeMessagingTransport.messageReceived_(e)); - assertEquals('tp', serviceResult); - assertEquals('SETUP', payloadResult); - assertEquals('Ensure channel name has been updated.', - 'new_channel', - t.channel_.name); - t.dispose(); -} - - -function createMockEvent(data) { - var event = {}; - event.getBrowserEvent = function() { return {data: data} }; - return event; -} - - -function getTestChannel(opt_domHelper) { - var cfg = {}; - cfg[goog.net.xpc.CfgFields.CHANNEL_NAME] = 'test_channel'; - return new goog.net.xpc.CrossPageChannel(cfg, opt_domHelper); -} - -</script> -</head> - -<body></body> - -</html> diff --git a/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/text-base/nixtransport.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/text-base/nixtransport.js.svn-base deleted file mode 100644 index d3b0dd7..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/text-base/nixtransport.js.svn-base +++ /dev/null @@ -1,473 +0,0 @@ -// Copyright 2008 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Contains the NIX (Native IE XDC) method transport for - * cross-domain communication. It exploits the fact that Internet Explorer - * allows a window that is the parent of an iframe to set said iframe window's - * opener property to an object. This object can be a function that in turn - * can be used to send a message despite same-origin constraints. Note that - * this function, if a pure JavaScript object, opens up the possibilitiy of - * gaining a hold of the context of the other window and in turn, attacking - * it. This implementation therefore wraps the JavaScript objects used inside - * a VBScript class. Since VBScript objects are passed in JavaScript as a COM - * wrapper (like DOM objects), they are thus opaque to JavaScript - * (except for the interface they expose). This therefore provides a safe - * method of transport. - * - * - * Initially based on FrameElementTransport which shares some similarities - * to this method. - */ - -goog.provide('goog.net.xpc.NixTransport'); - -goog.require('goog.net.xpc'); -goog.require('goog.net.xpc.CrossPageChannelRole'); -goog.require('goog.net.xpc.Transport'); -goog.require('goog.reflect'); - - -/** - * NIX method transport. - * - * NOTE(user): NIX method tested in all IE versions starting from 6.0. - * - * @param {goog.net.xpc.CrossPageChannel} channel The channel this transport - * belongs to. - * @param {goog.dom.DomHelper=} opt_domHelper The dom helper to use for finding - * the correct window. - * @constructor - * @extends {goog.net.xpc.Transport} - */ -goog.net.xpc.NixTransport = function(channel, opt_domHelper) { - goog.base(this, opt_domHelper); - - /** - * The channel this transport belongs to. - * @type {goog.net.xpc.CrossPageChannel} - * @private - */ - this.channel_ = channel; - - /** - * The authorization token, if any, used by this transport. - * @type {?string} - * @private - */ - this.authToken_ = channel[goog.net.xpc.CfgFields.AUTH_TOKEN] || ''; - - /** - * The authorization token, if any, that must be sent by the other party - * for setup to occur. - * @type {?string} - * @private - */ - this.remoteAuthToken_ = - channel[goog.net.xpc.CfgFields.REMOTE_AUTH_TOKEN] || ''; - - // Conduct the setup work for NIX in general, if need be. - goog.net.xpc.NixTransport.conductGlobalSetup_(this.getWindow()); - - // Setup aliases so that VBScript can call these methods - // on the transport class, even if they are renamed during - // compression. - this[goog.net.xpc.NixTransport.NIX_HANDLE_MESSAGE] = this.handleMessage_; - this[goog.net.xpc.NixTransport.NIX_CREATE_CHANNEL] = this.createChannel_; -}; -goog.inherits(goog.net.xpc.NixTransport, goog.net.xpc.Transport); - - -// Consts for NIX. VBScript doesn't allow items to start with _ for some -// reason, so we need to make these names quite unique, as they will go into -// the global namespace. - - -/** - * Global name of the Wrapper VBScript class. - * Note that this class will be stored in the *global* - * namespace (i.e. window in browsers). - * @type {string} - */ -goog.net.xpc.NixTransport.NIX_WRAPPER = 'GCXPC____NIXVBS_wrapper'; - - -/** - * Global name of the GetWrapper VBScript function. This - * constant is used by JavaScript to call this function. - * Note that this function will be stored in the *global* - * namespace (i.e. window in browsers). - * @type {string} - */ -goog.net.xpc.NixTransport.NIX_GET_WRAPPER = 'GCXPC____NIXVBS_get_wrapper'; - - -/** - * The name of the handle message method used by the wrapper class - * when calling the transport. - * @type {string} - */ -goog.net.xpc.NixTransport.NIX_HANDLE_MESSAGE = 'GCXPC____NIXJS_handle_message'; - - -/** - * The name of the create channel method used by the wrapper class - * when calling the transport. - * @type {string} - */ -goog.net.xpc.NixTransport.NIX_CREATE_CHANNEL = 'GCXPC____NIXJS_create_channel'; - - -/** - * A "unique" identifier that is stored in the wrapper - * class so that the wrapper can be distinguished from - * other objects easily. - * @type {string} - */ -goog.net.xpc.NixTransport.NIX_ID_FIELD = 'GCXPC____NIXVBS_container'; - - -/** - * Determines if the installed version of IE supports accessing window.opener - * after it has been set to a non-Window/null value. NIX relies on this being - * possible. - * @return {boolean} Whether window.opener behavior is compatible with NIX. - */ -goog.net.xpc.NixTransport.isNixSupported = function() { - var isSupported = false; - try { - var oldOpener = window.opener; - // The compiler complains (as it should!) if we set window.opener to - // something other than a window or null. - window.opener = /** @type {Window} */ ({}); - isSupported = goog.reflect.canAccessProperty(window, 'opener'); - window.opener = oldOpener; - } catch(e) { } - return isSupported; -}; - - -/** - * Conducts the global setup work for the NIX transport method. - * This function creates and then injects into the page the - * VBScript code necessary to create the NIX wrapper class. - * Note that this method can be called multiple times, as - * it internally checks whether the work is necessary before - * proceeding. - * @private - */ -goog.net.xpc.NixTransport.conductGlobalSetup_ = function(listenWindow) { - if (listenWindow['nix_setup_complete']) { - return; - } - - // Inject the VBScript code needed. - var vbscript = - // We create a class to act as a wrapper for - // a Javascript call, to prevent a break in of - // the context. - 'Class ' + goog.net.xpc.NixTransport.NIX_WRAPPER + '\n ' + - - // An internal member for keeping track of the - // transport for which this wrapper exists. - 'Private m_Transport\n' + - - // An internal member for keeping track of the - // auth token associated with the context that - // created this wrapper. Used for validation - // purposes. - 'Private m_Auth\n' + - - // Method for internally setting the value - // of the m_Transport property. We have the - // isEmpty check to prevent the transport - // from being overridden with an illicit - // object by a malicious party. - 'Public Sub SetTransport(transport)\n' + - 'If isEmpty(m_Transport) Then\n' + - 'Set m_Transport = transport\n' + - 'End If\n' + - 'End Sub\n' + - - // Method for internally setting the value - // of the m_Auth property. We have the - // isEmpty check to prevent the transport - // from being overridden with an illicit - // object by a malicious party. - 'Public Sub SetAuth(auth)\n' + - 'If isEmpty(m_Auth) Then\n' + - 'm_Auth = auth\n' + - 'End If\n' + - 'End Sub\n' + - - // Returns the auth token to the gadget, so it can - // confirm a match before initiating the connection - 'Public Function GetAuthToken()\n ' + - 'GetAuthToken = m_Auth\n' + - 'End Function\n' + - - // A wrapper method which causes a - // message to be sent to the other context. - 'Public Sub SendMessage(service, payload)\n ' + - 'Call m_Transport.' + - goog.net.xpc.NixTransport.NIX_HANDLE_MESSAGE + '(service, payload)\n' + - 'End Sub\n' + - - // Method for setting up the inner->outer - // channel. - 'Public Sub CreateChannel(channel)\n ' + - 'Call m_Transport.' + - goog.net.xpc.NixTransport.NIX_CREATE_CHANNEL + '(channel)\n' + - 'End Sub\n' + - - // An empty field with a unique identifier to - // prevent the code from confusing this wrapper - // with a run-of-the-mill value found in window.opener. - 'Public Sub ' + goog.net.xpc.NixTransport.NIX_ID_FIELD + '()\n ' + - 'End Sub\n' + - 'End Class\n ' + - - // Function to get a reference to the wrapper. - 'Function ' + - goog.net.xpc.NixTransport.NIX_GET_WRAPPER + '(transport, auth)\n' + - 'Dim wrap\n' + - 'Set wrap = New ' + goog.net.xpc.NixTransport.NIX_WRAPPER + '\n' + - 'wrap.SetTransport transport\n' + - 'wrap.SetAuth auth\n' + - 'Set ' + goog.net.xpc.NixTransport.NIX_GET_WRAPPER + ' = wrap\n' + - 'End Function'; - - try { - listenWindow.execScript(vbscript, 'vbscript'); - listenWindow['nix_setup_complete'] = true; - } - catch (e) { - goog.net.xpc.logger.severe( - 'exception caught while attempting global setup: ' + e); - } -}; - - -/** - * The transport type. - * @type {number} - * @protected - */ -goog.net.xpc.NixTransport.prototype.transportType = - goog.net.xpc.TransportTypes.NIX; - - -/** - * Keeps track of whether the local setup has completed (i.e. - * the initial work towards setting the channel up has been - * completed for this end). - * @type {boolean} - * @private - */ -goog.net.xpc.NixTransport.prototype.localSetupCompleted_ = false; - - -/** - * The NIX channel used to talk to the other page. This - * object is in fact a reference to a VBScript class - * (see above) and as such, is in fact a COM wrapper. - * When using this object, make sure to not access methods - * without calling them, otherwise a COM error will be thrown. - * @type {Object} - * @private - */ -goog.net.xpc.NixTransport.prototype.nixChannel_ = null; - - -/** - * Connect this transport. - */ -goog.net.xpc.NixTransport.prototype.connect = function() { - if (this.channel_.getRole() == goog.net.xpc.CrossPageChannelRole.OUTER) { - this.attemptOuterSetup_(); - } else { - this.attemptInnerSetup_(); - } -}; - - -/** - * Attempts to setup the channel from the perspective - * of the outer (read: container) page. This method - * will attempt to create a NIX wrapper for this transport - * and place it into the "opener" property of the inner - * page's window object. If it fails, it will continue - * to loop until it does so. - * - * @private - */ -goog.net.xpc.NixTransport.prototype.attemptOuterSetup_ = function() { - if (this.localSetupCompleted_) { - return; - } - - // Get shortcut to iframe-element that contains the inner - // page. - var innerFrame = this.channel_.iframeElement_; - - try { - // Attempt to place the NIX wrapper object into the inner - // frame's opener property. - innerFrame.contentWindow.opener = - this.getWindow()[goog.net.xpc.NixTransport.NIX_GET_WRAPPER] - (this, this.authToken_); - this.localSetupCompleted_ = true; - } - catch (e) { - goog.net.xpc.logger.severe( - 'exception caught while attempting setup: ' + e); - } - - // If the retry is necessary, reattempt this setup. - if (!this.localSetupCompleted_) { - this.getWindow().setTimeout(goog.bind(this.attemptOuterSetup_, this), 100); - } -}; - - -/** - * Attempts to setup the channel from the perspective - * of the inner (read: iframe) page. This method - * will attempt to *read* the opener object from the - * page's opener property. If it succeeds, this object - * is saved into nixChannel_ and the channel is confirmed - * with the container by calling CreateChannel with an instance - * of a wrapper for *this* page. Note that if this method - * fails, it will continue to loop until it succeeds. - * - * @private - */ -goog.net.xpc.NixTransport.prototype.attemptInnerSetup_ = function() { - if (this.localSetupCompleted_) { - return; - } - - try { - var opener = this.getWindow().opener; - - // Ensure that the object contained inside the opener - // property is in fact a NIX wrapper. - if (opener && goog.net.xpc.NixTransport.NIX_ID_FIELD in opener) { - this.nixChannel_ = opener; - - // Ensure that the NIX channel given to use is valid. - var remoteAuthToken = this.nixChannel_['GetAuthToken'](); - - if (remoteAuthToken != this.remoteAuthToken_) { - goog.net.xpc.logger.severe('Invalid auth token from other party'); - return; - } - - // Complete the construction of the channel by sending our own - // wrapper to the container via the channel they gave us. - this.nixChannel_['CreateChannel']( - this.getWindow()[goog.net.xpc.NixTransport.NIX_GET_WRAPPER](this, - this.authToken_)); - - this.localSetupCompleted_ = true; - - // Notify channel that the transport is ready. - this.channel_.notifyConnected_(); - } - } - catch (e) { - goog.net.xpc.logger.severe( - 'exception caught while attempting setup: ' + e); - return; - } - - // If the retry is necessary, reattempt this setup. - if (!this.localSetupCompleted_) { - this.getWindow().setTimeout(goog.bind(this.attemptInnerSetup_, this), 100); - } -}; - - -/** - * Internal method called by the inner page, via the - * NIX wrapper, to complete the setup of the channel. - * - * @param {Object} channel The NIX wrapper of the - * inner page. - * @private - */ -goog.net.xpc.NixTransport.prototype.createChannel_ = function(channel) { - // Verify that the channel is in fact a NIX wrapper. - if (typeof channel != 'unknown' || - !(goog.net.xpc.NixTransport.NIX_ID_FIELD in channel)) { - goog.net.xpc.logger.severe('Invalid NIX channel given to createChannel_'); - } - - this.nixChannel_ = channel; - - // Ensure that the NIX channel given to use is valid. - var remoteAuthToken = this.nixChannel_['GetAuthToken'](); - - if (remoteAuthToken != this.remoteAuthToken_) { - goog.net.xpc.logger.severe('Invalid auth token from other party'); - return; - } - - // Indicate to the CrossPageChannel that the channel is setup - // and ready to use. - this.channel_.notifyConnected_(); -}; - - -/** - * Internal method called by the other page, via the NIX wrapper, - * to deliver a message. - * @param {string} serviceName The name of the service the message is to be - * delivered to. - * @param {string} payload The message to process. - * @private - */ -goog.net.xpc.NixTransport.prototype.handleMessage_ = - function(serviceName, payload) { - - function deliveryHandler() { - this.channel_.deliver_(serviceName, payload); - } - - this.getWindow().setTimeout(goog.bind(deliveryHandler, this), 1); -}; - - -/** - * Sends a message. - * @param {string} service The name of the service the message is to be - * delivered to. - * @param {string} payload The message content. - */ -goog.net.xpc.NixTransport.prototype.send = function(service, payload) { - // Verify that the NIX channel we have is valid. - if (typeof(this.nixChannel_) !== 'unknown') { - goog.net.xpc.logger.severe('NIX channel not connected'); - } - - // Send the message via the NIX wrapper object. - this.nixChannel_['SendMessage'](service, payload); -}; - - -/** @override */ -goog.net.xpc.NixTransport.prototype.disposeInternal = function() { - goog.base(this, 'disposeInternal'); - this.nixChannel_ = null; -}; diff --git a/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/text-base/relay.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/text-base/relay.js.svn-base deleted file mode 100644 index a79e7a5..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/text-base/relay.js.svn-base +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright 2007 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Standalone script to be included in the relay-document - * used by goog.net.xpc.IframeRelayTransport. This script will decode the - * fragment identifier, determine the target window object and deliver - * the data to it. - * - */ - -goog.provide('goog.net.xpc.relay'); - -(function() { - // Decode the fragement identifier. - // location.href is expected to be structured as follows: - // <url>#<channel_name>[,<iframe_id>]|<data> - - // Get the fragment identifier. - var raw = window.location.hash; - if (!raw) { - return; - } - if (raw.charAt(0) == '#') { - raw = raw.substring(1); - } - var pos = raw.indexOf('|'); - var head = raw.substring(0, pos).split(','); - var channelName = head[0]; - var iframeId = head.length == 2 ? head[1] : null; - var frame = raw.substring(pos + 1); - - // Find the window object of the peer. - // - // The general structure of the frames looks like this: - // - peer1 - // - relay2 - // - peer2 - // - relay1 - // - // We are either relay1 or relay2. - - var win; - if (iframeId) { - // We are relay2 and need to deliver the data to peer2. - win = window.parent.frames[iframeId]; - } else { - // We are relay1 and need to deliver the data to peer1. - win = window.parent.parent; - } - - // Deliver the data. - try { - win['xpcRelay'](channelName, frame); - } catch (e) { - // Nothing useful can be done here. - // It would be great to inform the sender the delivery of this message - // failed, but this is not possible because we are already in the receiver's - // domain at this point. - } -})(); diff --git a/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/text-base/transport.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/text-base/transport.js.svn-base deleted file mode 100644 index b9148af..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/text-base/transport.js.svn-base +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright 2007 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Contains the base class for transports. - * - */ - - -goog.provide('goog.net.xpc.Transport'); - -goog.require('goog.Disposable'); -goog.require('goog.dom'); -goog.require('goog.net.xpc'); - - - -/** - * The base class for transports. - * @param {goog.dom.DomHelper=} opt_domHelper The dom helper to use for - * finding the window objects. - * @constructor - * @extends {goog.Disposable}; - */ -goog.net.xpc.Transport = function(opt_domHelper) { - goog.Disposable.call(this); - - /** - * The dom helper to use for finding the window objects to reference. - * @type {goog.dom.DomHelper} - * @private - */ - this.domHelper_ = opt_domHelper || goog.dom.getDomHelper(); -}; -goog.inherits(goog.net.xpc.Transport, goog.Disposable); - - -/** - * The transport type. - * @type {number} - * @protected - */ -goog.net.xpc.Transport.prototype.transportType = 0; - - -/** - * @return {number} The transport type identifier. - */ -goog.net.xpc.Transport.prototype.getType = function() { - return this.transportType; -}; - - -/** - * Returns the window associated with this transport instance. - * @return {Window} The window to use. - */ -goog.net.xpc.Transport.prototype.getWindow = function() { - return this.domHelper_.getWindow(); -}; - - -/** - * Return the transport name. - * @return {string} the transport name. - */ -goog.net.xpc.Transport.prototype.getName = function() { - return goog.net.xpc.TransportNames[this.transportType] || ''; -}; - - -/** - * Handles transport service messages (internal signalling). - * @param {string} payload The message content. - */ -goog.net.xpc.Transport.prototype.transportServiceHandler = goog.abstractMethod; - - -/** - * Connects this transport. - * The transport implementation is expected to call - * CrossPageChannel.prototype.notifyConnected_ when the channel is ready - * to be used. - */ -goog.net.xpc.Transport.prototype.connect = goog.abstractMethod; - - -/** - * Sends a message. - * @param {string} service The name off the service the message is to be - * delivered to. - * @param {string|Object} payload The message content. - */ -goog.net.xpc.Transport.prototype.send = goog.abstractMethod; diff --git a/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/text-base/xpc.js.svn-base b/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/text-base/xpc.js.svn-base deleted file mode 100644 index c74a349..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/xpc/.svn/text-base/xpc.js.svn-base +++ /dev/null @@ -1,238 +0,0 @@ -// Copyright 2007 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @fileoverview Provides the namesspace for client-side communication - * between pages originating from different domains (it works also - * with pages from the same domain, but doing that is kinda - * pointless). - * - * The only publicly visible class is goog.net.xpc.CrossPageChannel. - * - * Note: The preferred name for the main class would have been - * CrossDomainChannel. But as there already is a class named like - * that (which serves a different purpose) in the maps codebase, - * CrossPageChannel was chosen to avoid confusion. - * - * CrossPageChannel abstracts the underlying transport mechanism to - * provide a common interface in all browsers. - * - */ - -/* -TODO(user) -- resolve fastback issues in Safari (IframeRelayTransport) - */ - - -/** - * Namespace for CrossPageChannel - */ -goog.provide('goog.net.xpc'); -goog.provide('goog.net.xpc.CfgFields'); -goog.provide('goog.net.xpc.ChannelStates'); -goog.provide('goog.net.xpc.TransportNames'); -goog.provide('goog.net.xpc.TransportTypes'); -goog.provide('goog.net.xpc.UriCfgFields'); - -goog.require('goog.debug.Logger'); - - -/** - * Enum used to identify transport types. - * @enum {number} - */ -goog.net.xpc.TransportTypes = { - NATIVE_MESSAGING: 1, - FRAME_ELEMENT_METHOD: 2, - IFRAME_RELAY: 3, - IFRAME_POLLING: 4, - FLASH: 5, - NIX: 6 -}; - - -/** - * Enum containing transport names. These need to correspond to the - * transport class names for createTransport_() to work. - * @type {Object} - */ -goog.net.xpc.TransportNames = { - '1': 'NativeMessagingTransport', - '2': 'FrameElementMethodTransport', - '3': 'IframeRelayTransport', - '4': 'IframePollingTransport', - '5': 'FlashTransport', - '6': 'NixTransport' -}; - - -// TODO(user): Add auth token support to other methods. - - -/** - * Field names used on configuration object. - * @type {Object} - */ -goog.net.xpc.CfgFields = { - /** - * Channel name identifier. - * Both peers have to be initialized with - * the same channel name. If not present, a channel name is - * generated (which then has to transferred to the peer somehow). - */ - CHANNEL_NAME: 'cn', - /** - * Authorization token. If set, NIX will use this authorization token - * to validate the setup. - */ - AUTH_TOKEN: 'at', - /** - * Remote party's authorization token. If set, NIX will validate this - * authorization token against that sent by the other party. - */ - REMOTE_AUTH_TOKEN: 'rat', - /** - * The URI of the peer page. - */ - PEER_URI: 'pu', - /** - * Ifame-ID identifier. - * The id of the iframe element the peer-document lives in. - */ - IFRAME_ID: 'ifrid', - /** - * Transport type identifier. - * The transport type to use. Possible values are entries from - * goog.net.xpc.TransportTypes. If not present, the transport is - * determined automatically based on the useragent's capabilities. - */ - TRANSPORT: 'tp', - /** - * Local relay URI identifier (IframeRelayTransport-specific). - * The URI (can't contain a fragment identifier) used by the peer to - * relay data through. - */ - LOCAL_RELAY_URI: 'lru', - /** - * Peer relay URI identifier (IframeRelayTransport-specific). - * The URI (can't contain a fragment identifier) used to relay data - * to the peer. - */ - PEER_RELAY_URI: 'pru', - /** - * Local poll URI identifier (IframePollingTransport-specific). - * The URI (can't contain a fragment identifier)which is polled - * to receive data from the peer. - */ - LOCAL_POLL_URI: 'lpu', - /** - * Local poll URI identifier (IframePollingTransport-specific). - * The URI (can't contain a fragment identifier) used to send data - * to the peer. - */ - PEER_POLL_URI: 'ppu', - /** - * The hostname of the peer window, including protocol, domain, and port - * (if specified). Used for security sensitive applications that make - * use of NativeMessagingTransport (i.e. most applications). - */ - PEER_HOSTNAME: 'ph' -}; - - -/** - * Config properties that need to be URL sanitized. - * @type {Array}.<string> - */ -goog.net.xpc.UriCfgFields = [ - goog.net.xpc.CfgFields.PEER_URI, - goog.net.xpc.CfgFields.LOCAL_RELAY_URI, - goog.net.xpc.CfgFields.PEER_RELAY_URI, - goog.net.xpc.CfgFields.LOCAL_POLL_URI, - goog.net.xpc.CfgFields.PEER_POLL_URI -]; - - -/** - * @enum {number} - */ -goog.net.xpc.ChannelStates = { - NOT_CONNECTED: 1, - CONNECTED: 2, - CLOSED: 3 -}; - - -/** - * The name of the transport service (used for internal signalling). - * @type {string} - * @private - */ -goog.net.xpc.TRANSPORT_SERVICE_ = 'tp'; - - -/** - * Transport signaling message: setup. - * @protected - */ -goog.net.xpc.SETUP = 'SETUP'; - - -/** - * Transport signaling message: setup acknowledgement. - * @private - */ -goog.net.xpc.SETUP_ACK_ = 'SETUP_ACK'; - - -/** - * Object holding active channels. - * @type {Object} - * @private - */ -goog.net.xpc.channels_ = {}; - - -/** - * Returns a random string. - * @param {number} length How many characters the string shall contain. - * @param {string=} opt_characters The characters used. - * @return {string} The random string. - */ -goog.net.xpc.getRandomString = function(length, opt_characters) { - var chars = opt_characters || goog.net.xpc.randomStringCharacters_; - var charsLength = chars.length; - var s = ''; - while (length-- > 0) { - s += chars.charAt(Math.floor(Math.random() * charsLength)); - } - return s; -}; - - -/** - * The default characters used for random string generation. - * @type {string} - * @private - */ -goog.net.xpc.randomStringCharacters_ = - 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; - - -/** - * The logger. - * @type {goog.debug.Logger} - */ -goog.net.xpc.logger = goog.debug.Logger.getLogger('goog.net.xpc'); diff --git a/contexts/data/lib/closure-library/closure/goog/net/xpc/crosspagechannel.js b/contexts/data/lib/closure-library/closure/goog/net/xpc/crosspagechannel.js index f14e95e..171cad1 100644 --- a/contexts/data/lib/closure-library/closure/goog/net/xpc/crosspagechannel.js +++ b/contexts/data/lib/closure-library/closure/goog/net/xpc/crosspagechannel.js @@ -23,8 +23,11 @@ goog.provide('goog.net.xpc.CrossPageChannel'); goog.require('goog.Disposable'); goog.require('goog.Uri'); +goog.require('goog.async.Deferred'); +goog.require('goog.async.Delay'); goog.require('goog.dom'); goog.require('goog.events'); +goog.require('goog.events.EventHandler'); goog.require('goog.json'); goog.require('goog.messaging.AbstractChannel'); goog.require('goog.net.xpc'); @@ -68,7 +71,6 @@ goog.net.xpc.CrossPageChannel = function(cfg, opt_domHelper) { /** * The name of the channel. * @type {string} - * @protected */ this.name = this.cfg_[goog.net.xpc.CfgFields.CHANNEL_NAME] || goog.net.xpc.getRandomString(10); @@ -88,6 +90,13 @@ goog.net.xpc.CrossPageChannel = function(cfg, opt_domHelper) { */ this.deferredDeliveries_ = []; + /** + * An event handler used to listen for load events on peer iframes. + * @type {!goog.events.EventHandler} + * @private + */ + this.peerLoadHandler_ = new goog.events.EventHandler(this); + // If LOCAL_POLL_URI or PEER_POLL_URI is not available, try using // robots.txt from that host. cfg[goog.net.xpc.CfgFields.LOCAL_POLL_URI] = @@ -100,7 +109,7 @@ goog.net.xpc.CrossPageChannel = function(cfg, opt_domHelper) { goog.uri.utils.getHost(cfg[goog.net.xpc.CfgFields.PEER_URI] || '') + '/robots.txt'; - goog.net.xpc.channels_[this.name] = this; + goog.net.xpc.channels[this.name] = this; goog.events.listen(window, 'unload', goog.net.xpc.CrossPageChannel.disposeAll_); @@ -129,6 +138,25 @@ goog.net.xpc.CrossPageChannel.TRANSPORT_SERVICE_UNESCAPE_RE_ = /** + * A delay between the transport reporting as connected and the calling of the + * connection callback. Sometimes used to paper over timing vulnerabilities. + * @type {goog.async.Delay} + * @private + */ +goog.net.xpc.CrossPageChannel.prototype.connectionDelay_ = null; + + +/** + * A deferred which is set to non-null while a peer iframe is being created + * but has not yet thrown its load event, and which fires when that load event + * arrives. + * @type {goog.async.Deferred} + * @private + */ +goog.net.xpc.CrossPageChannel.prototype.peerWindowDeferred_ = null; + + +/** * The transport. * @type {goog.net.xpc.Transport?} * @private @@ -171,6 +199,28 @@ goog.net.xpc.CrossPageChannel.prototype.iframeElement_ = null; /** + * Returns the configuration object for this channel. + * Package private. Do not call from outside goog.net.xpc. + * + * @return {Object} The configuration object for this channel. + */ +goog.net.xpc.CrossPageChannel.prototype.getConfig = function() { + return this.cfg_; +}; + + +/** + * Returns a reference to the iframe-element. + * Package private. Do not call from outside goog.net.xpc. + * + * @return {Object} A reference to the iframe-element. + */ +goog.net.xpc.CrossPageChannel.prototype.getIframeElement = function() { + return this.iframeElement_; +}; + + +/** * Sets the window object the foreign document resides in. * * @param {Object} peerWindowObject The window object of the peer. @@ -182,6 +232,42 @@ goog.net.xpc.CrossPageChannel.prototype.setPeerWindowObject = /** + * Returns the window object the foreign document resides in. + * Package private. Do not call from outside goog.net.xpc. + * + * @return {Object} The window object of the peer. + */ +goog.net.xpc.CrossPageChannel.prototype.getPeerWindowObject = function() { + return this.peerWindowObject_; +}; + + +/** + * Determines whether the peer window is available (e.g. not closed). + * Package private. Do not call from outside goog.net.xpc. + * + * @return {boolean} Whether the peer window is available. + */ +goog.net.xpc.CrossPageChannel.prototype.isPeerAvailable = function() { + // NOTE(user): This check is not reliable in IE, where a document in an + // iframe does not get unloaded when removing the iframe element from the DOM. + // TODO(user): Find something that works in IE as well. + // NOTE(user): "!this.peerWindowObject_.closed" evaluates to 'false' in IE9 + // sometimes even though typeof(this.peerWindowObject_.closed) is boolean and + // this.peerWindowObject_.closed evaluates to 'false'. Casting it to a Boolean + // results in sane evaluation. When this happens, it's in the inner iframe + // when querying its parent's 'closed' status. Note that this is a different + // case than mibuerge@'s note above. + try { + return !!this.peerWindowObject_ && !Boolean(this.peerWindowObject_.closed); + } catch (e) { + // If the window is closing, an error may be thrown. + return false; + } +}; + + +/** * Determine which transport type to use for this channel / useragent. * @return {goog.net.xpc.TransportTypes|undefined} The best transport type. * @private @@ -226,10 +312,14 @@ goog.net.xpc.CrossPageChannel.prototype.createTransport_ = function() { switch (this.cfg_[goog.net.xpc.CfgFields.TRANSPORT]) { case goog.net.xpc.TransportTypes.NATIVE_MESSAGING: + var protocolVersion = this.cfg_[ + goog.net.xpc.CfgFields.NATIVE_TRANSPORT_PROTOCOL_VERSION] || 2; this.transport_ = new goog.net.xpc.NativeMessagingTransport( this, this.cfg_[goog.net.xpc.CfgFields.PEER_HOSTNAME], - this.domHelper_); + this.domHelper_, + !!this.cfg_[goog.net.xpc.CfgFields.ONE_SIDED_HANDSHAKE], + protocolVersion); break; case goog.net.xpc.TransportTypes.NIX: this.transport_ = new goog.net.xpc.NixTransport(this, this.domHelper_); @@ -283,6 +373,8 @@ goog.net.xpc.CrossPageChannel.prototype.getPeerConfiguration = function() { peerCfg[goog.net.xpc.CfgFields.CHANNEL_NAME] = this.name; peerCfg[goog.net.xpc.CfgFields.TRANSPORT] = this.cfg_[goog.net.xpc.CfgFields.TRANSPORT]; + peerCfg[goog.net.xpc.CfgFields.ONE_SIDED_HANDSHAKE] = + this.cfg_[goog.net.xpc.CfgFields.ONE_SIDED_HANDSHAKE]; if (this.cfg_[goog.net.xpc.CfgFields.LOCAL_RELAY_URI]) { peerCfg[goog.net.xpc.CfgFields.PEER_RELAY_URI] = @@ -296,6 +388,13 @@ goog.net.xpc.CrossPageChannel.prototype.getPeerConfiguration = function() { peerCfg[goog.net.xpc.CfgFields.LOCAL_POLL_URI] = this.cfg_[goog.net.xpc.CfgFields.PEER_POLL_URI]; } + var role = this.cfg_[goog.net.xpc.CfgFields.ROLE]; + if (role) { + peerCfg[goog.net.xpc.CfgFields.ROLE] = + role == goog.net.xpc.CrossPageChannelRole.INNER ? + goog.net.xpc.CrossPageChannelRole.OUTER : + goog.net.xpc.CrossPageChannelRole.INNER; + } return peerCfg; }; @@ -317,6 +416,7 @@ goog.net.xpc.CrossPageChannel.prototype.getPeerConfiguration = function() { */ goog.net.xpc.CrossPageChannel.prototype.createPeerIframe = function( parentElm, opt_configureIframeCb, opt_addCfgParam) { + goog.net.xpc.logger.info('createPeerIframe()'); var iframeId = this.cfg_[goog.net.xpc.CfgFields.IFRAME_ID]; if (!iframeId) { @@ -329,7 +429,7 @@ goog.net.xpc.CrossPageChannel.prototype.createPeerIframe = function( // TODO(user) Opera creates a history-entry when creating an iframe // programmatically as follows. Find a way which avoids this. - var iframeElm = goog.dom.createElement('IFRAME'); + var iframeElm = goog.dom.getDomHelper(parentElm).createElement('IFRAME'); iframeElm.id = iframeElm.name = iframeId; if (opt_configureIframeCb) { opt_configureIframeCb(iframeElm); @@ -337,21 +437,21 @@ goog.net.xpc.CrossPageChannel.prototype.createPeerIframe = function( iframeElm.style.width = iframeElm.style.height = '100%'; } + this.cleanUpIncompleteConnection_(); + this.peerWindowDeferred_ = + new goog.async.Deferred(undefined, this); var peerUri = this.getPeerUri(opt_addCfgParam); + this.peerLoadHandler_.listenOnce(iframeElm, 'load', + this.peerWindowDeferred_.callback, false, this.peerWindowDeferred_); if (goog.userAgent.GECKO || goog.userAgent.WEBKIT) { // Appending the iframe in a timeout to avoid a weird fastback issue, which // is present in Safari and Gecko. - this.deferConnect_ = true; window.setTimeout( goog.bind(function() { - this.deferConnect_ = false; parentElm.appendChild(iframeElm); iframeElm.src = peerUri.toString(); goog.net.xpc.logger.info('peer iframe created (' + iframeId + ')'); - if (this.connectDeferred_) { - this.connect(this.connectCb_); - } }, this), 1); } else { iframeElm.src = peerUri.toString(); @@ -364,6 +464,22 @@ goog.net.xpc.CrossPageChannel.prototype.createPeerIframe = function( /** + * Clean up after any incomplete attempt to establish and connect to a peer + * iframe. + * @private + */ +goog.net.xpc.CrossPageChannel.prototype.cleanUpIncompleteConnection_ = + function() { + if (this.peerWindowDeferred_) { + this.peerWindowDeferred_.cancel(); + this.peerWindowDeferred_ = null; + } + this.deferredDeliveries_.length = 0; + this.peerLoadHandler_.removeAll(); +}; + + +/** * Returns the peer URI, with an optional URL parameter for configuring the peer * window. * @@ -390,22 +506,6 @@ goog.net.xpc.CrossPageChannel.prototype.getPeerUri = function(opt_addCfgParam) { /** - * Flag whether connecting should be deferred. - * @type {boolean} - * @private - */ -goog.net.xpc.CrossPageChannel.prototype.deferConnect_ = false; - - -/** - * Flag to remember if connect() has been called. - * @type {boolean} - * @private - */ -goog.net.xpc.CrossPageChannel.prototype.connectDeferred_ = false; - - -/** * Initiates connecting the channel. When this method is called, all the * information needed to connect the channel has to be available. * @@ -416,14 +516,24 @@ goog.net.xpc.CrossPageChannel.prototype.connectDeferred_ = false; goog.net.xpc.CrossPageChannel.prototype.connect = function(opt_connectCb) { this.connectCb_ = opt_connectCb || goog.nullFunction; - if (this.deferConnect_) { - goog.net.xpc.logger.info('connect() deferred'); - this.connectDeferred_ = true; - return; + // If we know of a peer window whose creation has been requested but is not + // complete, peerWindowDeferred_ will be non-null, and we should block on it. + if (this.peerWindowDeferred_) { + this.peerWindowDeferred_.addCallback(this.continueConnection_); + } else { + this.continueConnection_(); } - this.connectDeferred_ = false; +}; + - goog.net.xpc.logger.info('connect()'); +/** + * Continues the connection process once we're as sure as we can be that the + * peer iframe has been created. + * @private + */ +goog.net.xpc.CrossPageChannel.prototype.continueConnection_ = function() { + goog.net.xpc.logger.info('continueConnection_()'); + this.peerWindowDeferred_ = null; if (this.cfg_[goog.net.xpc.CfgFields.IFRAME_ID]) { this.iframeElement_ = this.domHelper_.getElement( this.cfg_[goog.net.xpc.CfgFields.IFRAME_ID]); @@ -441,7 +551,7 @@ goog.net.xpc.CrossPageChannel.prototype.connect = function(opt_connectCb) { // being in an iframe and the channel is meant to be to the containing page if (!this.peerWindowObject_) { // throw an error if we are in the top window (== not in an iframe) - if (window == top) { + if (window == window.top) { throw Error( "CrossPageChannel: Can't connect, peer window-object not set."); } else { @@ -464,36 +574,55 @@ goog.net.xpc.CrossPageChannel.prototype.connect = function(opt_connectCb) { * Closes the channel. */ goog.net.xpc.CrossPageChannel.prototype.close = function() { - if (!this.isConnected()) return; + this.cleanUpIncompleteConnection_(); this.state_ = goog.net.xpc.ChannelStates.CLOSED; - this.transport_.dispose(); + goog.dispose(this.transport_); this.transport_ = null; this.connectCb_ = null; - this.connectDeferred_ = false; - this.deferredDeliveries_.length = 0; + goog.dispose(this.connectionDelay_); + this.connectionDelay_ = null; goog.net.xpc.logger.info('Channel "' + this.name + '" closed'); }; /** + * Package-private. * Called by the transport when the channel is connected. - * @private + * @param {number=} opt_delay Delay this number of milliseconds before calling + * the connection callback. Usage is discouraged, but can be used to paper + * over timing vulnerabilities when there is no alternative. */ -goog.net.xpc.CrossPageChannel.prototype.notifyConnected_ = function() { - if (this.isConnected()) { +goog.net.xpc.CrossPageChannel.prototype.notifyConnected = function(opt_delay) { + if (this.isConnected() || + (this.connectionDelay_ && this.connectionDelay_.isActive())) { return; } this.state_ = goog.net.xpc.ChannelStates.CONNECTED; goog.net.xpc.logger.info('Channel "' + this.name + '" connected'); - this.connectCb_(); + goog.dispose(this.connectionDelay_); + if (opt_delay) { + this.connectionDelay_ = + new goog.async.Delay(this.connectCb_, opt_delay); + this.connectionDelay_.start(); + } else { + this.connectionDelay_ = null; + this.connectCb_(); + } }; /** - * Called by the transport in case of an unrecoverable failure. + * Alias for notifyConected, for backward compatibility reasons. * @private */ -goog.net.xpc.CrossPageChannel.prototype.notifyTransportError_ = function() { +goog.net.xpc.CrossPageChannel.prototype.notifyConnected_ = + goog.net.xpc.CrossPageChannel.prototype.notifyConnected; + + +/** + * Called by the transport in case of an unrecoverable failure. + */ +goog.net.xpc.CrossPageChannel.prototype.notifyTransportError = function() { goog.net.xpc.logger.info('Transport Error'); this.close(); }; @@ -506,16 +635,7 @@ goog.net.xpc.CrossPageChannel.prototype.send = function(serviceName, payload) { return; } // Check if the peer is still around. - // NOTE(user): This check is not reliable in IE, where a document in an - // iframe does not get unloaded when removing the iframe element from the DOM. - // TODO(user): Find something that works in IE as well. - // NOTE(user): "!this.peerWindowObject_.closed" evaluates to 'false' in IE9 - // sometimes even though typeof(this.peerWindowObject_.closed) is boolean and - // this.peerWindowObject_.closed evaluates to 'false'. Casting it to a Boolean - // results in sane evaluation. When this happens, it's in the inner iframe - // when querying its parent's 'closed' status. Note that this is a different - // case than mibuerge@'s note above. - if (Boolean(this.peerWindowObject_.closed)) { + if (!this.isPeerAvailable()) { goog.net.xpc.logger.severe('Peer has disappeared.'); this.close(); return; @@ -532,7 +652,11 @@ goog.net.xpc.CrossPageChannel.prototype.send = function(serviceName, payload) { /** - * Delivers messages to the appropriate service-handler. + * Delivers messages to the appropriate service-handler. Named xpcDeliver to + * avoid name conflict with {@code deliver} function in superclass + * goog.messaging.AbstractChannel. + * + * Package private. Do not call from outside goog.net.xpc. * * @param {string} serviceName The name of the port. * @param {string} payload The payload. @@ -540,19 +664,18 @@ goog.net.xpc.CrossPageChannel.prototype.send = function(serviceName, payload) { * underlying transport makes that available. If this is specified, and * the PEER_HOSTNAME parameter was provided, they must match or the message * will be rejected. - * @private */ -goog.net.xpc.CrossPageChannel.prototype.deliver_ = function( +goog.net.xpc.CrossPageChannel.prototype.xpcDeliver = function( serviceName, payload, opt_origin) { - // This covers the very rare (but producable) case where the inner frame + // This check covers the very rare (but producable) case where the inner frame // becomes ready and sends its setup message while the outer frame is - // deferring its connect method waiting for the inner frame to be ready. - // Without it that message can be passed to deliver_, which is unable to - // process it because the channel is not yet fully configured. - if (this.connectDeferred_) { + // deferring its connect method waiting for the inner frame to be ready. The + // resulting deferral ensures the message will not be processed until the + // channel is fully configured. + if (this.peerWindowDeferred_) { this.deferredDeliveries_.push( - goog.bind(this.deliver_, this, serviceName, payload, opt_origin)); + goog.bind(this.xpcDeliver, this, serviceName, payload, opt_origin)); return; } @@ -564,7 +687,7 @@ goog.net.xpc.CrossPageChannel.prototype.deliver_ = function( } if (this.isDisposed()) { - goog.net.xpc.logger.warning('CrossPageChannel::deliver_(): Disposed.'); + goog.net.xpc.logger.warning('CrossPageChannel::xpcDeliver(): Disposed.'); } else if (!serviceName || serviceName == goog.net.xpc.TRANSPORT_SERVICE_) { this.transport_.transportServiceHandler(payload); @@ -573,7 +696,8 @@ goog.net.xpc.CrossPageChannel.prototype.deliver_ = function( if (this.isConnected()) { this.deliver(this.unescapeServiceName_(serviceName), payload); } else { - goog.net.xpc.logger.info('CrossPageChannel::deliver_(): Not connected.'); + goog.net.xpc.logger.info( + 'CrossPageChannel::xpcDeliver(): Not connected.'); } } }; @@ -622,9 +746,14 @@ goog.net.xpc.CrossPageChannel.prototype.unescapeServiceName_ = function(name) { * @return {number} The role of this channel. */ goog.net.xpc.CrossPageChannel.prototype.getRole = function() { - return window.parent == this.peerWindowObject_ ? - goog.net.xpc.CrossPageChannelRole.INNER : - goog.net.xpc.CrossPageChannelRole.OUTER; + var role = this.cfg_[goog.net.xpc.CfgFields.ROLE]; + if (role) { + return role; + } else { + return window.parent == this.peerWindowObject_ ? + goog.net.xpc.CrossPageChannelRole.INNER : + goog.net.xpc.CrossPageChannelRole.OUTER; + } }; @@ -648,14 +777,14 @@ goog.net.xpc.CrossPageChannel.prototype.isMessageOriginAcceptable_ = function( /** @override */ goog.net.xpc.CrossPageChannel.prototype.disposeInternal = function() { - goog.base(this, 'disposeInternal'); - this.close(); this.peerWindowObject_ = null; this.iframeElement_ = null; - delete goog.net.xpc.channels_[this.name]; - this.deferredDeliveries_.length = 0; + delete goog.net.xpc.channels[this.name]; + goog.dispose(this.peerLoadHandler_); + delete this.peerLoadHandler_; + goog.base(this, 'disposeInternal'); }; @@ -664,10 +793,7 @@ goog.net.xpc.CrossPageChannel.prototype.disposeInternal = function() { * @private */ goog.net.xpc.CrossPageChannel.disposeAll_ = function() { - for (var name in goog.net.xpc.channels_) { - var ch = goog.net.xpc.channels_[name]; - if (ch) { - ch.dispose(); - } + for (var name in goog.net.xpc.channels) { + goog.dispose(goog.net.xpc.channels[name]); } }; diff --git a/contexts/data/lib/closure-library/closure/goog/net/xpc/crosspagechannel_test.html b/contexts/data/lib/closure-library/closure/goog/net/xpc/crosspagechannel_test.html index 7b895b8..0c77626 100644 --- a/contexts/data/lib/closure-library/closure/goog/net/xpc/crosspagechannel_test.html +++ b/contexts/data/lib/closure-library/closure/goog/net/xpc/crosspagechannel_test.html @@ -11,10 +11,11 @@ See the COPYING file for details. <head> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>CrossPageChannel: End-to-End Test</title> -<script src="../../base.js"></script> -<script> +<script type="text/javascript" src="../../base.js"></script> +<script type="text/javascript"> goog.require('goog.Disposable'); goog.require('goog.Uri'); + goog.require('goog.async.Deferred'); goog.require('goog.debug.Logger'); goog.require('goog.dom'); goog.require('goog.net.xpc.CrossPageChannel'); @@ -25,18 +26,25 @@ See the COPYING file for details. </script> </head> <body> -<script> +<script type="text/javascript"> -var IFRAME_LOAD_WAIT_MS = 2000; +// Set this to false when working on this test. It needs to be true for +// automated testing, as some browsers (eg IE8) choke on the large numbers of +// iframes this test would otherwise leave active. +var CLEAN_UP_IFRAMES = true; + +var IFRAME_LOAD_WAIT_MS = 1000; var stubs = new goog.testing.PropertyReplacer(); var asyncTestCase = goog.testing.AsyncTestCase.createAndInstall( document.title); var uniqueId = 0; var driver; - +var canAccessSameDomainIframe = true; +var accessCheckIframes = []; function setUpPage() { - asyncTestCase.stepTimeout = 10 * 1000; + // This test is insanely slow on IE8 for some reason. + asyncTestCase.stepTimeout = 20 * 1000; // Show debug log var debugDiv = goog.dom.getElement('debugDiv'); @@ -47,6 +55,8 @@ function setUpPage() { msgElm.innerHTML = logRecord.getMessage(); goog.dom.appendChild(debugDiv, msgElm); }); + asyncTestCase.waitForAsync('Checking if we can access same domain iframes'); + checkSameDomainIframeAccess(); } @@ -61,13 +71,42 @@ function tearDown() { } +function checkSameDomainIframeAccess() { + accessCheckIframes.push( + create1x1Iframe('nonexistant', 'testdata/i_am_non_existant.html')); + window.setTimeout(function () { + accessCheckIframes.push( + create1x1Iframe('existant', 'testdata/access_checker.html')); + }, 10); +} + + +function create1x1Iframe(iframeId, src) { + var iframeAccessChecker = goog.dom.createElement('IFRAME'); + iframeAccessChecker.id = iframeAccessChecker.name = iframeId; + iframeAccessChecker.style.width = iframeAccessChecker.style.height = '1px'; + iframeAccessChecker.src = src; + document.body.insertBefore(iframeAccessChecker, document.body.firstChild); + return iframeAccessChecker; +} + + +function sameDomainIframeAccessComplete(canAccess) { + canAccessSameDomainIframe = canAccess; + for (var i = 0; i < accessCheckIframes.length; i++) { + document.body.removeChild(accessCheckIframes[i]); + } + asyncTestCase.continueTesting(); +} + + function testCreateIframeSpecifyId() { driver.createPeerIframe('new_iframe'); asyncTestCase.waitForAsync('iframe load'); window.setTimeout(function() { - asyncTestCase.continueTesting(); driver.checkPeerIframe(); + asyncTestCase.continueTesting(); }, IFRAME_LOAD_WAIT_MS); } @@ -77,44 +116,298 @@ function testCreateIframeRandomId() { asyncTestCase.waitForAsync('iframe load'); window.setTimeout(function() { - asyncTestCase.continueTesting(); driver.checkPeerIframe(); + asyncTestCase.continueTesting(); }, IFRAME_LOAD_WAIT_MS); } -function testCreateIframeWithDom() { - driver.createPeerIframe(goog.dom.getDomHelper()); +// The following batch of tests: +// * Establishes a peer iframe +// * Connects an XPC channel between the frames +// * From the connection callback in each frame, sends an 'echo' request, and +// expects a 'response' response. +// * Reconnects the inner frame, sends an 'echo', expects a 'response'. +// * Optionally, reconnects the outer frame, sends an 'echo', expects a +// 'response'. +// * Optionally, reconnects the inner frame, but first reconfigures it to the +// alternate protocol version, simulating an inner frame navigation that +// picks up a new/old version. +// +// Every valid combination of protocol versions is tested, with both single and +// double ended handshakes. Two timing scenarios are tested per combination, +// which is what the 'reverse' parameter distinguishes. +// +// Where single sided handshake is in use, reconnection by the outer frame is +// not supported, and therefore is not tested. +// +// The only known issue migrating to V2 is that once two V2 peers have +// connected, replacing either peer with a V1 peer will not work. Upgrading V1 +// peers to v2 is supported, as is replacing the only v2 peer in a connection +// with a v1. + + +function testLifeCycle_v1_v1() { + checkLifeCycle( + false /* oneSidedHandshake */, + 1 /* innerProtocolVersion */, + 1 /* outerProtocolVersion */, + true /* outerFrameReconnectSupported */, + true /* innerFrameMigrationSupported */, + false /* reverse */); +} - asyncTestCase.waitForAsync('iframe load'); - window.setTimeout(function() { - asyncTestCase.continueTesting(); - driver.checkPeerIframe(); - }, IFRAME_LOAD_WAIT_MS); + +function testLifeCycle_v1_v1_rev() { + checkLifeCycle( + false /* oneSidedHandshake */, + 1 /* innerProtocolVersion */, + 1 /* outerProtocolVersion */, + true /* outerFrameReconnectSupported */, + true /* innerFrameMigrationSupported */, + true /* reverse */); } -function testCreateIframeAsynchronousConnect() { - driver.createPeerIframe('new_iframe'); +function testLifeCycle_v1_v1_onesided() { + checkLifeCycle( + true /* oneSidedHandshake */, + 1 /* innerProtocolVersion */, + 1 /* outerProtocolVersion */, + false /* outerFrameReconnectSupported */, + true /* innerFrameMigrationSupported */, + false /* reverse */); +} - asyncTestCase.waitForAsync('iframe load'); - window.setTimeout(function() { - driver.connect(); - }, IFRAME_LOAD_WAIT_MS); + +function testLifeCycle_v1_v1_onesided_rev() { + checkLifeCycle( + true /* oneSidedHandshake */, + 1 /* innerProtocolVersion */, + 1 /* outerProtocolVersion */, + false /* outerFrameReconnectSupported */, + true /* innerFrameMigrationSupported */, + true /* reverse */); } -function testCreateIframeSynchronousConnect() { - driver.createPeerIframe('new_iframe'); - driver.connect(); +function testLifeCycle_v1_v2() { + checkLifeCycle( + false /* oneSidedHandshake */, + 1 /* innerProtocolVersion */, + 2 /* outerProtocolVersion */, + true /* outerFrameReconnectSupported */, + true /* innerFrameMigrationSupported */, + false /* reverse */); +} + + +function testLifeCycle_v1_v2_rev() { + checkLifeCycle( + false /* oneSidedHandshake */, + 1 /* innerProtocolVersion */, + 2 /* outerProtocolVersion */, + true /* outerFrameReconnectSupported */, + true /* innerFrameMigrationSupported */, + true /* reverse */); +} + + +function testLifeCycle_v1_v2_onesided() { + checkLifeCycle( + true /* oneSidedHandshake */, + 1 /* innerProtocolVersion */, + 2 /* outerProtocolVersion */, + false /* outerFrameReconnectSupported */, + true /* innerFrameMigrationSupported */, + false /* reverse */); +} + + +function testLifeCycle_v1_v2_onesided_rev() { + checkLifeCycle( + true /* oneSidedHandshake */, + 1 /* innerProtocolVersion */, + 2 /* outerProtocolVersion */, + false /* outerFrameReconnectSupported */, + true /* innerFrameMigrationSupported */, + true /* reverse */); +} + + +function testLifeCycle_v2_v1() { + checkLifeCycle( + false /* oneSidedHandshake */, + 2 /* innerProtocolVersion */, + 1 /* outerProtocolVersion */, + true /* outerFrameReconnectSupported */, + true /* innerFrameMigrationSupported */, + false /* reverse */); +} + + +function testLifeCycle_v2_v1_rev() { + checkLifeCycle( + false /* oneSidedHandshake */, + 2 /* innerProtocolVersion */, + 1 /* outerProtocolVersion */, + true /* outerFrameReconnectSupported */, + true /* innerFrameMigrationSupported */, + true /* reverse */); +} + + +function testLifeCycle_v2_v1_onesided() { + checkLifeCycle( + true /* oneSidedHandshake */, + 2 /* innerProtocolVersion */, + 1 /* outerProtocolVersion */, + false /* outerFrameReconnectSupported */, + true /* innerFrameMigrationSupported */, + false /* reverse */); +} + + +function testLifeCycle_v2_v1_onesided_rev() { + checkLifeCycle( + true /* oneSidedHandshake */, + 2 /* innerProtocolVersion */, + 1 /* outerProtocolVersion */, + false /* outerFrameReconnectSupported */, + true /* innerFrameMigrationSupported */, + true /* reverse */); +} + + +function testLifeCycle_v2_v2() { + checkLifeCycle( + false /* oneSidedHandshake */, + 2 /* innerProtocolVersion */, + 2 /* outerProtocolVersion */, + true /* outerFrameReconnectSupported */, + false /* innerFrameMigrationSupported */, + false /* reverse */); +} + + +function testLifeCycle_v2_v2_rev() { + checkLifeCycle( + false /* oneSidedHandshake */, + 2 /* innerProtocolVersion */, + 2 /* outerProtocolVersion */, + true /* outerFrameReconnectSupported */, + false /* innerFrameMigrationSupported */, + true /* reverse */); +} + + +function testLifeCycle_v2_v2_onesided() { + checkLifeCycle( + true /* oneSidedHandshake */, + 2 /* innerProtocolVersion */, + 2 /* outerProtocolVersion */, + false /* outerFrameReconnectSupported */, + false /* innerFrameMigrationSupported */, + false /* reverse */); +} + + +function testLifeCycle_v2_v2_onesided_rev() { + checkLifeCycle( + true /* oneSidedHandshake */, + 2 /* innerProtocolVersion */, + 2 /* outerProtocolVersion */, + false /* outerFrameReconnectSupported */, + false /* innerFrameMigrationSupported */, + true /* reverse */); +} + + +function checkLifeCycle(oneSidedHandshake, innerProtocolVersion, + outerProtocolVersion, outerFrameReconnectSupported, + innerFrameMigrationSupported, reverse) { + driver.createPeerIframe('new_iframe', oneSidedHandshake, + innerProtocolVersion, outerProtocolVersion); + driver.connect(true /* fullLifeCycleTest */, outerFrameReconnectSupported, + innerFrameMigrationSupported, reverse); } -function testExistingIframeConnect() { - driver.createChannel('test_iframe'); - driver.connect(); +function testConnectMismatchedNames_v1_v1() { + checkConnectMismatchedNames( + 1 /* innerProtocolVersion */, + 1 /* outerProtocolVersion */, + false /* reverse */); } + +function testConnectMismatchedNames_v1_v1_rev() { + checkConnectMismatchedNames( + 1 /* innerProtocolVersion */, + 1 /* outerProtocolVersion */, + true /* reverse */); +} + + +function testConnectMismatchedNames_v1_v2() { + checkConnectMismatchedNames( + 1 /* innerProtocolVersion */, + 2 /* outerProtocolVersion */, + false /* reverse */); +} + + +function testConnectMismatchedNames_v1_v2_rev() { + checkConnectMismatchedNames( + 1 /* innerProtocolVersion */, + 2 /* outerProtocolVersion */, + true /* reverse */); +} + + +function testConnectMismatchedNames_v2_v1() { + checkConnectMismatchedNames( + 2 /* innerProtocolVersion */, + 1 /* outerProtocolVersion */, + false /* reverse */); +} + + +function testConnectMismatchedNames_v2_v1_rev() { + checkConnectMismatchedNames( + 2 /* innerProtocolVersion */, + 1 /* outerProtocolVersion */, + true /* reverse */); +} + + +function testConnectMismatchedNames_v2_v2() { + checkConnectMismatchedNames( + 2 /* innerProtocolVersion */, + 2 /* outerProtocolVersion */, + false /* reverse */); +} + + +function testConnectMismatchedNames_v2_v2_rev() { + checkConnectMismatchedNames( + 2 /* innerProtocolVersion */, + 2 /* outerProtocolVersion */, + true /* reverse */); +} + + +function checkConnectMismatchedNames(innerProtocolVersion, + outerProtocolVersion, reverse) { + driver.createPeerIframe('new_iframe', false /* oneSidedHandshake */, innerProtocolVersion, + outerProtocolVersion, true /* opt_randomChannelNames */); + driver.connect(false /* fullLifeCycleTest */, + false /* outerFrameReconnectSupported */, + false /* innerFrameMigrationSupported */, + false /* reverse */); +} + + function testEscapeServiceName() { var escape = goog.net.xpc.CrossPageChannel.prototype.escapeServiceName_; assertEquals('Shouldn\'t escape alphanumeric name', @@ -130,34 +423,40 @@ function testEscapeServiceName() { assertEquals('Should not escape s%tp', 's%25tp', escape('s%tp')); } + function testSameDomainCheck_noMessageOrigin() { var channel = new goog.net.xpc.CrossPageChannel(goog.object.create( goog.net.xpc.CfgFields.PEER_HOSTNAME, 'http://foo.com')); assertTrue(channel.isMessageOriginAcceptable_(undefined)); } + function testSameDomainCheck_noPeerHostname() { var channel = new goog.net.xpc.CrossPageChannel({}); assertTrue(channel.isMessageOriginAcceptable_('http://foo.com')); } + function testSameDomainCheck_unconfigured() { var channel = new goog.net.xpc.CrossPageChannel({}); assertTrue(channel.isMessageOriginAcceptable_(undefined)); } + function testSameDomainCheck_originsMatch() { var channel = new goog.net.xpc.CrossPageChannel(goog.object.create( goog.net.xpc.CfgFields.PEER_HOSTNAME, 'http://foo.com')); assertTrue(channel.isMessageOriginAcceptable_('http://foo.com')); } + function testSameDomainCheck_originsMismatch() { var channel = new goog.net.xpc.CrossPageChannel(goog.object.create( goog.net.xpc.CfgFields.PEER_HOSTNAME, 'http://foo.com')); assertFalse(channel.isMessageOriginAcceptable_('http://nasty.com')); } + function testUnescapeServiceName() { var unescape = goog.net.xpc.CrossPageChannel.prototype.unescapeServiceName_; assertEquals('Shouldn\'t modify alphanumeric name', @@ -175,6 +474,18 @@ function testUnescapeServiceName() { /** + * Tests the case where the channel is disposed before it is fully connected. + */ +function testDisposeBeforeConnect() { + asyncTestCase.waitForAsync('Checking disposal before connection.') + driver.createPeerIframe('new_iframe', false /* oneSidedHandshake */, + 2 /* innerProtocolVersion */, 2 /* outerProtocolVersion */, + true /* opt_randomChannelNames */); + driver.connectOuterAndDispose(); +} + + +/** * Driver for the tests for CrossPageChannel. * * @constructor @@ -191,36 +502,79 @@ Driver = function() { this.iframe_ = null; /** - * The ID of the peer iframe. - * @type {string} + * The channel to use. + * @type {goog.net.xpc.CrossPageChannel} * @private */ - this.iframeId_ = 'test_iframe'; + this.channel_ = null; /** - * Channel configuration object. + * Outer frame configuration object. * @type {Object} * @private */ - this.cfg_ = null; + this.outerFrameCfg_ = null; /** - * The channel to use. - * @type {goog.net.xpc.CrossPageChannel} + * The initial name of the outer channel. + * @type {?string} * @private */ - this.channel_ = null; + this.initialOuterChannelName_ = null; + + /** + * Inner frame configuration object. + * @type {Object} + * @private + */ + this.innerFrameCfg_ = null; + + /** + * The contents of the payload of the 'echo' request sent by the inner frame. + * @type {?string} + * @private + */ + this.innerFrameEchoPayload_ = null; + + /** + * The contents of the payload of the 'echo' request sent by the outer frame. + * @type {?string} + * @private + */ + this.outerFrameEchoPayload_ = null; + + /** + * A deferred which fires when the inner frame receives its echo response. + * @type {goog.async.Deferred} + * @private + */ + this.innerFrameResponseReceived_ = new goog.async.Deferred(); + + /** + * A deferred which fires when the outer frame receives its echo response. + * @type {goog.async.Deferred} + * @private + */ + this.outerFrameResponseReceived_ = new goog.async.Deferred(); + }; goog.inherits(Driver, goog.Disposable); /** @override */ Driver.prototype.disposeInternal = function() { - goog.base(this, 'disposeInternal'); - - if (this.channel_) { - this.channel_.dispose(); + // Required to make this test perform acceptably (and pass) on slow browsers, + // esp IE8. + if (CLEAN_UP_IFRAMES) { + goog.dom.removeNode(this.iframe_); + delete this.iframe_; } + goog.dispose(this.channel_); + this.innerFrameResponseReceived_.cancel(); + this.innerFrameResponseReceived_ = null; + this.outerFrameResponseReceived_.cancel(); + this.outerFrameResponseReceived_ = null; + goog.base(this, 'disposeInternal'); }; @@ -230,27 +584,44 @@ Driver.prototype.disposeInternal = function() { * @private */ Driver.prototype.getInnerPeer_ = function() { - return window.frames[this.iframeId_]; + return this.iframe_.contentWindow; }; /** - * Creates the channel. + * Sets up the configuration objects for the inner and outer frames. * @param {string=} opt_iframeId If present, the ID of the iframe to use, * otherwise, tells the channel to generate an iframe ID. - * @param {goog.dom.DomHelper=} opt_domHelper The optional dom helper to use - * for determining which window to use. + * @param {boolean=} opt_oneSidedHandshake Whether the one sided handshake + * config option should be set. + * @param {string=} opt_channelName The name of the channel to use, or null + * to generate one. + * @param {number=} opt_innerProtocolVersion The native transport protocol + * version used in the inner iframe. + * @param {number=} opt_outerProtocolVersion The native transport protocol + * version used in the outer iframe. + * @param {boolean=} randomChannelNames Whether the different ends of the + * channel should be allowed to pick differing, random names. + * @return {string} The name of the created channel. + * @private */ -Driver.prototype.createChannel = function(opt_iframeId, opt_domHelper) { +Driver.prototype.setConfiguration_ = function(opt_iframeId, + opt_oneSidedHandshake, opt_channelName, opt_innerProtocolVersion, + opt_outerProtocolVersion, opt_randomChannelNames) { var cfg = {}; if (opt_iframeId) { - this.iframeId_ = opt_iframeId; cfg[goog.net.xpc.CfgFields.IFRAME_ID] = opt_iframeId; } cfg[goog.net.xpc.CfgFields.PEER_URI] = 'testdata/inner_peer.html'; - cfg[goog.net.xpc.CfgFields.CHANNEL_NAME] = 'test_channel' + uniqueId++; + if (!opt_randomChannelNames) { + var channelName = opt_channelName || 'test_channel' + uniqueId++; + cfg[goog.net.xpc.CfgFields.CHANNEL_NAME] = channelName; + } cfg[goog.net.xpc.CfgFields.LOCAL_POLL_URI] = 'does-not-exist.html'; cfg[goog.net.xpc.CfgFields.PEER_POLL_URI] = 'does-not-exist.html'; + cfg[goog.net.xpc.CfgFields.ONE_SIDED_HANDSHAKE] = !!opt_oneSidedHandshake; + cfg[goog.net.xpc.CfgFields.NATIVE_TRANSPORT_PROTOCOL_VERSION] = + opt_outerProtocolVersion; function resolveUri(fieldName) { cfg[fieldName] = goog.Uri.resolve(window.location.href, cfg[fieldName]).toString(); @@ -258,10 +629,60 @@ Driver.prototype.createChannel = function(opt_iframeId, opt_domHelper) { resolveUri(goog.net.xpc.CfgFields.PEER_URI); resolveUri(goog.net.xpc.CfgFields.LOCAL_POLL_URI); resolveUri(goog.net.xpc.CfgFields.PEER_POLL_URI); + this.outerFrameCfg_ = cfg; + this.innerFrameCfg_ = goog.object.clone(cfg); + this.innerFrameCfg_[ + goog.net.xpc.CfgFields.NATIVE_TRANSPORT_PROTOCOL_VERSION] = + opt_innerProtocolVersion; +}; - this.channel_ = new goog.net.xpc.CrossPageChannel(cfg, opt_domHelper); - this.channel_.registerService('msg', goog.bind(this.msgHandler_, this)); - this.cfg_ = cfg; + +/** + * Creates an outer frame channel object. + * @private + */ +Driver.prototype.createChannel_ = function() { + if (this.channel_) { + this.channel_.dispose(); + } + this.channel_ = new goog.net.xpc.CrossPageChannel(this.outerFrameCfg_); + this.channel_.registerService('echo', + goog.bind(this.echoHandler_, this)); + this.channel_.registerService('response', + goog.bind(this.responseHandler_, this)); + + return this.channel_.name; +}; + + +/** + * Checks the names of the inner and outer frames meet expectations. + * @private + */ +Driver.prototype.checkChannelNames_ = function() { + var outerName = this.channel_.name; + var innerName = this.getInnerPeer_().channel.name; + var configName = this.innerFrameCfg_[goog.net.xpc.CfgFields.CHANNEL_NAME] + || null; + + // The outer channel never changes its name. + assertEquals(this.initialOuterChannelName_, outerName); + // The name should be as configured, if it was configured. + if (configName) { + assertEquals(configName, innerName); + } + // The names of both ends of the channel should match. + assertEquals(innerName, outerName); + G_testRunner.log('Channel name: ' + innerName); +}; + + +/** + * Returns the configuration of the xpc. + * @return {?Object} The configuration of the xpc. + */ +Driver.prototype.getInnerFrameConfiguration = function() { + return this.innerFrameCfg_; }; @@ -269,10 +690,20 @@ Driver.prototype.createChannel = function(opt_iframeId, opt_domHelper) { * Creates the peer iframe. * @param {string=} opt_iframeId If present, the ID of the iframe to create, * otherwise, generates an iframe ID. - * @param {goog.dom.DomHelper=} opt_domHelper The dom helper to use for - * finding the elements in the iframe. + * @param {boolean=} opt_oneSidedHandshake Whether a one sided handshake is + * specified. + * @param {number=} opt_innerProtocolVersion The native transport protocol + * version used in the inner iframe. + * @param {number=} opt_outerProtocolVersion The native transport protocol + * version used in the outer iframe. + * @param {boolean=} opt_randomChannelNames Whether the ends of the channel + * should be allowed to pick differing, random names. + * @return {!Array.<string>} The id of the created iframe and the name of the + * created channel. */ -Driver.prototype.createPeerIframe = function(opt_iframeId, opt_domHelper) { +Driver.prototype.createPeerIframe = function(opt_iframeId, + opt_oneSidedHandshake, opt_innerProtocolVersion, opt_outerProtocolVersion, + opt_randomChannelNames) { var expectedIframeId; if (opt_iframeId) { @@ -287,11 +718,14 @@ Driver.prototype.createPeerIframe = function(opt_iframeId, opt_domHelper) { assertNull('element[id=' + expectedIframeId + '] exists', goog.dom.getElement(expectedIframeId)); - this.createChannel(opt_iframeId, opt_domHelper); + this.setConfiguration_(opt_iframeId, opt_oneSidedHandshake, + undefined /* opt_channelName */, opt_innerProtocolVersion, + opt_outerProtocolVersion, opt_randomChannelNames); + var channelName = this.createChannel_(); + this.initialOuterChannelName_ = channelName; this.iframe_ = this.channel_.createPeerIframe(document.body); assertEquals(expectedIframeId, this.iframe_.id); - this.iframeId_ = expectedIframeId; }; @@ -299,7 +733,7 @@ Driver.prototype.createPeerIframe = function(opt_iframeId, opt_domHelper) { * Checks if the peer iframe has been created. */ Driver.prototype.checkPeerIframe = function() { - assertNotNull(goog.dom.getElement(this.iframeId_)); + assertNotNull(this.iframe_); var peer = this.getInnerPeer_(); assertNotNull(peer); assertNotNull(peer.document); @@ -309,112 +743,282 @@ Driver.prototype.checkPeerIframe = function() { /** * Starts the connection. The connection happens asynchronously. */ -Driver.prototype.connect = function() { - // TODO(user): Get tests to pass for all transports +Driver.prototype.connect = function(fullLifeCycleTest, + outerFrameReconnectSupported, innerFrameMigrationSupported, reverse) { if (!this.isTransportTestable_()) { asyncTestCase.continueTesting(); return; } - if (this.iframe_) { - // When we create an iframe, we send the config - // and it connects itself. - this.childConnected_(); + asyncTestCase.waitForAsync('parent and child connect'); + + // Set the criteria for the initial handshake portion of the test. + this.reinitializeDeferreds_(); + this.innerFrameResponseReceived_.awaitDeferred( + this.outerFrameResponseReceived_); + this.innerFrameResponseReceived_.addCallback( + goog.bind(this.checkChannelNames_, this)); + + if (fullLifeCycleTest) { + this.innerFrameResponseReceived_.addCallback( + goog.bind(this.testReconnects_, this, + outerFrameReconnectSupported, innerFrameMigrationSupported)); } else { - asyncTestCase.waitForAsync('parent and child connect'); - var peer = this.getInnerPeer_(); - peer.instantiateChannel(this.cfg_); - peer.connectChannel(goog.bind(this.childConnected_, this)); + this.innerFrameResponseReceived_.addCallback( + goog.bind(asyncTestCase.continueTesting, asyncTestCase)); + } + + this.continueConnect_(reverse); +}; + + +Driver.prototype.continueConnect_ = function(reverse) { + // Wait until the peer is fully established. Establishment is sometimes very + // slow indeed, especially on virtual machines, so a fixed timeout is not + // suitable. This wait is required because we want to take precise control + // of the channel startup timing, and shouldn't be needed in production use, + // where the inner frame's channel is typically not started by a DOM call as + // it is here. + if (!this.getInnerPeer_() || !this.getInnerPeer_().instantiateChannel) { + window.setTimeout(goog.bind(this.continueConnect_, this, reverse), 100); + return; } - this.channel_.connect(goog.bind(this.parentConnected_, this)); + var connectFromOuterFrame = goog.bind(this.channel_.connect, this.channel_, + goog.bind(this.outerFrameConnected_, this)); + var innerConfig = this.innerFrameCfg_; + var connectFromInnerFrame = goog.bind(this.getInnerPeer_().instantiateChannel, + this.getInnerPeer_(), innerConfig); + + // Take control of the timing and reverse of each frame's first SETUP call. If + // these happen to fire right on top of each other, that tends to mask + // problems that reliably occur when there is a short delay. + window.setTimeout(connectFromOuterFrame, reverse ? 1 : 10); + window.setTimeout(connectFromInnerFrame, reverse ? 10 : 1); }; /** - * Determines if the transport type for the channel is testable. - * Some transports are misusing global state or making other - * assumptions that cause connections to fail. - * @return {boolean} Whether the transport is testable. + * Called by the outer frame connection callback. * @private */ -Driver.prototype.isTransportTestable_ = function() { - var testable = true; +Driver.prototype.outerFrameConnected_ = function() { + var payload = this.outerFrameEchoPayload_ = + goog.net.xpc.getRandomString(10); + this.channel_.send('echo', payload); +}; - var transportType = this.channel_.determineTransportType_(); - switch (transportType) { - case goog.net.xpc.TransportTypes.NATIVE_MESSAGING: - case goog.net.xpc.TransportTypes.IFRAME_RELAY: - case goog.net.xpc.TransportTypes.IFRAME_POLLING: - case goog.net.xpc.TransportTypes.FLASH: - case goog.net.xpc.TransportTypes.NIX: - testable = false; - break; - } - return testable; +/** + * Called by the inner frame connection callback. + */ +Driver.prototype.innerFrameConnected = function() { + var payload = this.innerFrameEchoPayload_ = + goog.net.xpc.getRandomString(10); + this.getInnerPeer_().sendEcho(payload); +}; + + +/** + * The handler function for incoming echo requests. + * @param {string} payload The message payload. + * @private + */ +Driver.prototype.echoHandler_ = function(payload) { + assertTrue('outer frame should be connected', this.channel_.isConnected()); + var peer = this.getInnerPeer_(); + assertTrue('child should be connected', peer.isConnected()); + this.channel_.send('response', payload); }; /** - * Callback for the parent connection. + * The handler function for incoming echo responses. + * @param {string} payload The message payload. * @private */ -Driver.prototype.parentConnected_ = function() { +Driver.prototype.responseHandler_ = function(payload) { + assertTrue('outer frame should be connected', this.channel_.isConnected()); var peer = this.getInnerPeer_(); - if (peer.isConnected()) { - asyncTestCase.waitForAsync('child echo'); + assertTrue('child should be connected', peer.isConnected()); + assertEquals(this.outerFrameEchoPayload_, payload); + this.outerFrameResponseReceived_.callback(true); +}; + + +/** + * The handler function for incoming echo replies. + * @param {string} payload The message payload. + * @private + */ +Driver.prototype.innerFrameGotResponse = function(payload) { + assertTrue('outer frame should be connected', this.channel_.isConnected()); + var peer = this.getInnerPeer_(); + assertTrue('child should be connected', peer.isConnected()); + assertEquals(this.innerFrameEchoPayload_, payload); + this.innerFrameResponseReceived_.callback(true); +}; + + +/** + * The second phase of the standard test, where reconnections of both the inner + * and outer frames are performed. + * @param {boolean} outerFrameReconnectSupported Whether outer frame reconnects + * are supported, and should be tested. + * @private + */ +Driver.prototype.testReconnects_ = function(outerFrameReconnectSupported, + innerFrameMigrationSupported) { + G_testRunner.log('Performing inner frame reconnect'); + this.reinitializeDeferreds_(); + this.innerFrameResponseReceived_.addCallback( + goog.bind(this.checkChannelNames_, this)); + + if (outerFrameReconnectSupported) { + this.innerFrameResponseReceived_.addCallback( + goog.bind(this.performOuterFrameReconnect_, this, + innerFrameMigrationSupported)); + } else if (innerFrameMigrationSupported) { + this.innerFrameResponseReceived_.addCallback( + goog.bind(this.migrateInnerFrame_, this)); } else { - asyncTestCase.waitForAsync('child connect'); + this.innerFrameResponseReceived_.addCallback( + goog.bind(asyncTestCase.continueTesting, asyncTestCase)); } - this.channel_.send('echo', 'hello') + this.performInnerFrameReconnect_(); }; /** - * Callback for the child connection. + * Initializes the deferreds and clears the echo payloads, ready for another + * sub-test. * @private */ -Driver.prototype.childConnected_ = function() { - if (this.channel_.isConnected()) { - asyncTestCase.waitForAsync('child echo'); +Driver.prototype.reinitializeDeferreds_ = function() { + this.innerFrameEchoPayload_ = null; + this.outerFrameEchoPayload_ = null; + this.innerFrameResponseReceived_.cancel(); + this.innerFrameResponseReceived_ = new goog.async.Deferred(); + this.outerFrameResponseReceived_.cancel(); + this.outerFrameResponseReceived_ = new goog.async.Deferred(); +}; + + +/** + * Get the inner frame to reconnect, and repeat the echo test. + * @private + */ +Driver.prototype.performInnerFrameReconnect_ = function() { + var peer = this.getInnerPeer_(); + peer.instantiateChannel(this.innerFrameCfg_); +}; + + +/** + * Get the outer frame to reconnect, and repeat the echo test. + * @private + */ +Driver.prototype.performOuterFrameReconnect_ = function( + innerFrameMigrationSupported) { + G_testRunner.log('Reconnecting outer frame'); + this.reinitializeDeferreds_(); + this.innerFrameResponseReceived_.addCallback( + goog.bind(this.checkChannelNames_, this)); + if (innerFrameMigrationSupported) { + this.outerFrameResponseReceived_.addCallback( + goog.bind(this.migrateInnerFrame_, this)); } else { - asyncTestCase.waitForAsync('parent connect'); + this.outerFrameResponseReceived_.addCallback( + goog.bind(asyncTestCase.continueTesting, asyncTestCase)); } + this.createChannel_(); + this.channel_.connect(goog.bind(this.outerFrameConnected_, this)); }; /** - * The handler function for incoming msg requests. - * @param {string} payload The message payload. + * Migrate the inner frame to the alternate protocol version and reconnect it. * @private */ -Driver.prototype.msgHandler_ = function(payload) { - assertTrue('parent should be connected', this.channel_.isConnected()); - var peer = this.getInnerPeer_(); - assertTrue('child should be connected', peer.isConnected()); - assertEquals('hello', payload); +Driver.prototype.migrateInnerFrame_ = function() { + G_testRunner.log('Migrating inner frame'); + this.reinitializeDeferreds_(); + var innerFrameProtoVersion = this.innerFrameCfg_[ + goog.net.xpc.CfgFields.NATIVE_TRANSPORT_PROTOCOL_VERSION]; + this.innerFrameResponseReceived_.addCallback( + goog.bind(this.checkChannelNames_, this)); + this.innerFrameResponseReceived_.addCallback( + goog.bind(asyncTestCase.continueTesting, asyncTestCase)); + this.innerFrameCfg_[ + goog.net.xpc.CfgFields.NATIVE_TRANSPORT_PROTOCOL_VERSION] = + innerFrameProtoVersion == 1 ? 2 : 1; + this.performInnerFrameReconnect_(); +}; - asyncTestCase.continueTesting(); + +/** + * Determines if the transport type for the channel is testable. + * Some transports are misusing global state or making other + * assumptions that cause connections to fail. + * @return {boolean} Whether the transport is testable. + * @private + */ +Driver.prototype.isTransportTestable_ = function() { + var testable = false; + + var transportType = this.channel_.determineTransportType_(); + switch (transportType) { + case goog.net.xpc.TransportTypes.IFRAME_RELAY: + case goog.net.xpc.TransportTypes.IFRAME_POLLING: + testable = canAccessSameDomainIframe; + break; + case goog.net.xpc.TransportTypes.NATIVE_MESSAGING: + case goog.net.xpc.TransportTypes.FLASH: + case goog.net.xpc.TransportTypes.NIX: + testable = true; + break; + } + + return testable; +}; + + +/** + * Connect the outer channel but not the inner one. Wait a short time, then + * dispose the outer channel and make sure it was torn down properly. + */ +Driver.prototype.connectOuterAndDispose = function() { + this.channel_.connect(); + window.setTimeout(goog.bind(this.disposeAndCheck_, this), 2000); }; +/** + * Dispose the cross-page channel. Check that the transport was also + * disposed, and allow to run briefly to make sure no timers which will cause + * failures are still running. + */ +Driver.prototype.disposeAndCheck_ = function() { + assertFalse(this.channel_.isConnected()); + var transport = this.channel_.transport_; + this.channel_.dispose(); + assertNull(this.channel_.transport_); + assertTrue(this.channel_.isDisposed()); + assertTrue(transport.isDisposed()); + + // Let any errors caused by erroneous retries happen. + window.setTimeout(goog.bind(asyncTestCase.continueTesting, asyncTestCase), + 2000); +}; + </script> <!-- Debug box. --> -<div style="position:absolute; float: right; top: 10px; right: 10px"> +<div style="position:absolute; float: right; top: 10px; right: 10px; width: 500px"> Debug [<a href="#" onclick="document.getElementById('debugDiv').innerHTML = '';">clear</a>]: <br/> -<div id="debugDiv" style="border: 1px #000000 solid; font-size:xx-small"></div> +<div id="debugDiv" style="border: 1px #000000 solid; font-size:xx-small; background: #fff;"></div> </div> -<!-- -Setup inner peer. This must be done in the <body>, so that the inner peer iframe -blocks the onload event in this window until it is fully loaded. The JsUnit -tests will execute after the onload event fires. ---> -<iframe name=test_iframe id=test_iframe src=testdata/inner_peer.html width=300 height=250> -</iframe> - </body> </html> diff --git a/contexts/data/lib/closure-library/closure/goog/net/xpc/frameelementmethodtransport.js b/contexts/data/lib/closure-library/closure/goog/net/xpc/frameelementmethodtransport.js index f99ed6f..0b601dd 100644 --- a/contexts/data/lib/closure-library/closure/goog/net/xpc/frameelementmethodtransport.js +++ b/contexts/data/lib/closure-library/closure/goog/net/xpc/frameelementmethodtransport.js @@ -78,9 +78,10 @@ goog.inherits(goog.net.xpc.FrameElementMethodTransport, goog.net.xpc.Transport); * The transport type. * @type {number} * @protected + * @override */ goog.net.xpc.FrameElementMethodTransport.prototype.transportType = - goog.net.xpc.TransportTypes.FRAME_ELEMENT_METHOD; + goog.net.xpc.TransportTypes.FRAME_ELEMENT_METHOD; /** @@ -110,11 +111,12 @@ goog.net.xpc.FrameElementMethodTransport.outgoing_ = null; /** * Connect this transport. + * @override */ goog.net.xpc.FrameElementMethodTransport.prototype.connect = function() { if (this.channel_.getRole() == goog.net.xpc.CrossPageChannelRole.OUTER) { // get shortcut to iframe-element - this.iframeElm_ = this.channel_.iframeElement_; + this.iframeElm_ = this.channel_.getIframeElement(); // add the gateway function to the iframe-element // (to be called by the peer) @@ -157,7 +159,7 @@ goog.net.xpc.FrameElementMethodTransport.prototype.attemptSetup_ = function() { // notify outer frame this.send(goog.net.xpc.TRANSPORT_SERVICE_, goog.net.xpc.SETUP_ACK_); // notify channel that the transport is ready - this.channel_.notifyConnected_(); + this.channel_.notifyConnected(); } } catch (e) { @@ -177,6 +179,7 @@ goog.net.xpc.FrameElementMethodTransport.prototype.attemptSetup_ = function() { /** * Handles transport service messages. * @param {string} payload The message content. + * @override */ goog.net.xpc.FrameElementMethodTransport.prototype.transportServiceHandler = function(payload) { @@ -185,7 +188,7 @@ goog.net.xpc.FrameElementMethodTransport.prototype.transportServiceHandler = // get a reference to the gateway function this.outgoing_ = this.iframeElm_['XPC_toOuter']['XPC_toInner']; // notify the channel we're ready - this.channel_.notifyConnected_(); + this.channel_.notifyConnected(); } else { throw Error('Got unexpected transport message.'); } @@ -202,7 +205,7 @@ goog.net.xpc.FrameElementMethodTransport.prototype.transportServiceHandler = goog.net.xpc.FrameElementMethodTransport.prototype.incoming_ = function(serviceName, payload) { if (!this.recursive_ && this.queue_.length == 0) { - this.channel_.deliver_(serviceName, payload); + this.channel_.xpcDeliver(serviceName, payload); } else { this.queue_.push({serviceName: serviceName, payload: payload}); @@ -221,7 +224,7 @@ goog.net.xpc.FrameElementMethodTransport.prototype.deliverQueued_ = function() { while (this.queue_.length) { var msg = this.queue_.shift(); - this.channel_.deliver_(msg.serviceName, msg.payload); + this.channel_.xpcDeliver(msg.serviceName, msg.payload); } }; @@ -231,6 +234,7 @@ goog.net.xpc.FrameElementMethodTransport.prototype.deliverQueued_ = * @param {string} service The name off the service the message is to be * delivered to. * @param {string} payload The message content. + * @override */ goog.net.xpc.FrameElementMethodTransport.prototype.send = function(service, payload) { diff --git a/contexts/data/lib/closure-library/closure/goog/net/xpc/iframepollingtransport.js b/contexts/data/lib/closure-library/closure/goog/net/xpc/iframepollingtransport.js index aaa96ae..9f52c44 100644 --- a/contexts/data/lib/closure-library/closure/goog/net/xpc/iframepollingtransport.js +++ b/contexts/data/lib/closure-library/closure/goog/net/xpc/iframepollingtransport.js @@ -60,14 +60,16 @@ goog.net.xpc.IframePollingTransport = function(channel, opt_domHelper) { * @type {string} * @private */ - this.sendUri_ = this.channel_.cfg_[goog.net.xpc.CfgFields.PEER_POLL_URI]; + this.sendUri_ = + this.channel_.getConfig()[goog.net.xpc.CfgFields.PEER_POLL_URI]; /** * The URI which is polled for incoming messages. * @type {string} * @private */ - this.rcvUri_ = this.channel_.cfg_[goog.net.xpc.CfgFields.LOCAL_POLL_URI]; + this.rcvUri_ = + this.channel_.getConfig()[goog.net.xpc.CfgFields.LOCAL_POLL_URI]; /** * The queue to hold messages which can't be sent immediately. @@ -80,12 +82,23 @@ goog.inherits(goog.net.xpc.IframePollingTransport, goog.net.xpc.Transport); /** + * The number of times the inner frame will check for evidence of the outer + * frame before it tries its reconnection sequence. These occur at 100ms + * intervals, making this an effective max waiting period of 500ms. + * @type {number} + * @private + */ +goog.net.xpc.IframePollingTransport.prototype.pollsBeforeReconnect_ = 5; + + +/** * The transport type. * @type {number} * @protected + * @override */ goog.net.xpc.IframePollingTransport.prototype.transportType = - goog.net.xpc.TransportTypes.IFRAME_POLLING; + goog.net.xpc.TransportTypes.IFRAME_POLLING; /** @@ -113,6 +126,14 @@ goog.net.xpc.IframePollingTransport.prototype.initialized_ = false; /** + * Reconnection iframe created by inner peer. + * @type {Element} + * @private + */ +goog.net.xpc.IframePollingTransport.prototype.reconnectFrame_ = null; + + +/** * The string used to prefix all iframe names and IDs. * @type {string} */ @@ -142,14 +163,55 @@ goog.net.xpc.IframePollingTransport.prototype.getAckFrameName_ = function() { /** + * Determines whether the channel is still available. The channel is + * unavailable if the transport was disposed or the peer is no longer + * available. + * @return {boolean} Whether the channel is available. + */ +goog.net.xpc.IframePollingTransport.prototype.isChannelAvailable = function() { + return !this.isDisposed() && this.channel_.isPeerAvailable(); +}; + + +/** + * Safely retrieves the frames from the peer window. If an error is thrown + * (e.g. the window is closing) an empty frame object is returned. + * @return {!Object.<!Window>} The frames from the peer window. + * @private + */ +goog.net.xpc.IframePollingTransport.prototype.getPeerFrames_ = function() { + try { + if (this.isChannelAvailable()) { + return this.channel_.getPeerWindowObject().frames || {}; + } + } catch (e) { + // An error may be thrown if the window is closing. + goog.net.xpc.logger.fine('error retrieving peer frames'); + } + return {}; +}; + + +/** + * Safely retrieves the peer frame with the specified name. + * @param {string} frameName The name of the peer frame to retrieve. + * @return {Window} The peer frame with the specified name. + * @private + */ +goog.net.xpc.IframePollingTransport.prototype.getPeerFrame_ = function( + frameName) { + return this.getPeerFrames_()[frameName]; +}; + + +/** * Connects this transport. + * @override */ goog.net.xpc.IframePollingTransport.prototype.connect = function() { - if (this.isDisposed()) { - // We should stop polling for connecting if the transport has been - // disposed (i.e., the channel has been closed), otherwise - // outerPeerReconnect_() may throw exceptions when it refers - // channel_.peerWindowObject_ which is reset to null by channel_.close(). + if (!this.isChannelAvailable()) { + // When the channel is unavailable there is no peer to poll so stop trying + // to connect. return; } @@ -211,16 +273,25 @@ goog.net.xpc.IframePollingTransport.prototype.constructSenderFrame_ = * of bfcached iframes. * @private */ -goog.net.xpc.IframePollingTransport.prototype.innerPeerReconnect_ = function() { - goog.net.xpc.logger.finest('innerPeerReconnect called'); +goog.net.xpc.IframePollingTransport.prototype.maybeInnerPeerReconnect_ = + function() { + // Reconnection has been found to not function on some browsers (eg IE7), so + // it's important that the mechanism only be triggered as a last resort. As + // such, we poll a number of times to find the outer iframe before triggering + // it. + if (this.reconnectFrame_ || this.pollsBeforeReconnect_-- > 0) { + return; + } + + goog.net.xpc.logger.finest('Inner peer reconnect triggered.'); this.channel_.name = goog.net.xpc.getRandomString(10); goog.net.xpc.logger.finest('switching channels: ' + this.channel_.name); this.deconstructSenderFrames_(); this.initialized_ = false; // Communicate new channel name to outer peer. this.reconnectFrame_ = this.constructSenderFrame_( - goog.net.xpc.IframePollingTransport.IFRAME_PREFIX + - '_reconnect_' + this.channel_.name); + goog.net.xpc.IframePollingTransport.IFRAME_PREFIX + + '_reconnect_' + this.channel_.name); }; @@ -233,7 +304,7 @@ goog.net.xpc.IframePollingTransport.prototype.innerPeerReconnect_ = function() { */ goog.net.xpc.IframePollingTransport.prototype.outerPeerReconnect_ = function() { goog.net.xpc.logger.finest('outerPeerReconnect called'); - var frames = this.channel_.peerWindowObject_.frames; + var frames = this.getPeerFrames_(); var length = frames.length; for (var i = 0; i < length; i++) { var frameName; @@ -296,13 +367,13 @@ goog.net.xpc.IframePollingTransport.prototype.checkForeignFramesReady_ = this.isRcvFrameReady_(this.getAckFrameName_()))) { goog.net.xpc.logger.finest('foreign frames not (yet) present'); - if (this.channel_.getRole() == goog.net.xpc.CrossPageChannelRole.INNER && - !this.reconnectFrame_) { - // The inner peer should always have its receiving frames ready. - // It is safe to assume the channel name has fallen out of sync - // (which happens with bfcached frames). Create "reconnect" frames, - // which the outer peer will find, and use to resync the channel names. - this.innerPeerReconnect_(); + if (this.channel_.getRole() == goog.net.xpc.CrossPageChannelRole.INNER) { + // The outer peer might need a short time to get its frames ready, as + // CrossPageChannel prevents them from getting created until the inner + // peer's frame has thrown its loaded event. This method is a noop for + // the first few times it's called, and then allows the reconnection + // sequence to begin. + this.maybeInnerPeerReconnect_(); } else if (this.channel_.getRole() == goog.net.xpc.CrossPageChannelRole.OUTER) { // The inner peer is either not loaded yet, or the receiving @@ -319,11 +390,11 @@ goog.net.xpc.IframePollingTransport.prototype.checkForeignFramesReady_ = // Create receivers. this.msgReceiver_ = new goog.net.xpc.IframePollingTransport.Receiver( this, - this.channel_.peerWindowObject_.frames[this.getMsgFrameName_()], + this.getPeerFrame_(this.getMsgFrameName_()), goog.bind(this.processIncomingMsg, this)); this.ackReceiver_ = new goog.net.xpc.IframePollingTransport.Receiver( this, - this.channel_.peerWindowObject_.frames[this.getAckFrameName_()], + this.getPeerFrame_(this.getAckFrameName_()), goog.bind(this.processIncomingAck, this)); this.checkLocalFramesPresent_(); @@ -342,7 +413,7 @@ goog.net.xpc.IframePollingTransport.prototype.isRcvFrameReady_ = goog.net.xpc.logger.finest('checking for receive frame: ' + frameName); /** @preserveTry */ try { - var winObj = this.channel_.peerWindowObject_.frames[frameName]; + var winObj = this.getPeerFrame_(frameName); if (!winObj || winObj.location.href.indexOf(this.rcvUri_) != 0) { return false; } @@ -363,7 +434,7 @@ goog.net.xpc.IframePollingTransport.prototype.checkLocalFramesPresent_ = // Are the sender frames ready? // These contain a document from the peer's domain, therefore we can only // check if the frame itself is present. - var frames = this.channel_.peerWindowObject_.frames; + var frames = this.getPeerFrames_(); if (!(frames[this.getAckFrameName_()] && frames[this.getMsgFrameName_()])) { // start a timer to check again @@ -398,7 +469,7 @@ goog.net.xpc.IframePollingTransport.prototype.checkLocalFramesPresent_ = */ goog.net.xpc.IframePollingTransport.prototype.checkIfConnected_ = function() { if (this.sentConnectionSetupAck_ && this.rcvdConnectionSetupAck_) { - this.channel_.notifyConnected_(); + this.channel_.notifyConnected(); if (this.deliveryQueue_) { goog.net.xpc.logger.fine('delivering queued messages ' + @@ -406,7 +477,7 @@ goog.net.xpc.IframePollingTransport.prototype.checkIfConnected_ = function() { for (var i = 0, m; i < this.deliveryQueue_.length; i++) { m = this.deliveryQueue_[i]; - this.channel_.deliver_(m.service, m.payload); + this.channel_.xpcDeliver(m.service, m.payload); } delete this.deliveryQueue_; } @@ -551,7 +622,7 @@ goog.net.xpc.IframePollingTransport.prototype.deliverPayload_ = function(s) { push({service: service, payload: payload}); goog.net.xpc.logger.finest('queued delivery'); } else { - this.channel_.deliver_(service, payload); + this.channel_.xpcDeliver(service, payload); } }; @@ -574,6 +645,7 @@ goog.net.xpc.IframePollingTransport.prototype.MAX_FRAME_LENGTH_ = 3800; * * @param {string} service Name of service this the message has to be delivered. * @param {string} payload The message content. + * @override */ goog.net.xpc.IframePollingTransport.prototype.send = function(service, payload) { @@ -653,23 +725,25 @@ goog.net.xpc.IframePollingTransport.TIME_SHORT_POLL_AFTER_ACTIVITY_ = * @private */ goog.net.xpc.IframePollingTransport.receive_ = function() { + var receivers = goog.net.xpc.IframePollingTransport.receivers_; + var receiver; var rcvd = false; + /** @preserveTry */ try { - for (var i = 0, l = goog.net.xpc.IframePollingTransport.receivers_.length; - i < l; i++) { - rcvd = rcvd || - goog.net.xpc.IframePollingTransport.receivers_[i].receive(); + for (var i = 0; receiver = receivers[i]; i++) { + rcvd = rcvd || receiver.receive(); } } catch (e) { goog.net.xpc.logger.info('receive_() failed: ' + e); + // Notify the channel that the transport had an error. - goog.net.xpc.IframePollingTransport.receivers_[i]. - transport_.channel_.notifyTransportError_(); - // notifyTransportError_() closes the channel and dispoases the transport. + receiver.transport_.channel_.notifyTransportError(); + + // notifyTransportError() closes the channel and disposes the transport. // If there are no other channels present, this.receivers_ will now be empty - // and there is not need to keep polling. - if (!goog.net.xpc.IframePollingTransport.receivers_.length) { + // and there is no need to keep polling. + if (!receivers.length) { return; } } @@ -787,7 +861,8 @@ goog.net.xpc.IframePollingTransport.Sender.prototype.send = function(payload) { * goog.net.xpc.IframePollingTransport.Receiver * * @constructor - * @param {goog.net.xpc.Transport} transport The transport to receive from. + * @param {goog.net.xpc.IframePollingTransport} transport The transport to + * receive from. * @param {Object} windowObj The window-object to poll for location-changes. * @param {Function} callback The callback-function to be called when * location has changed. @@ -795,12 +870,15 @@ goog.net.xpc.IframePollingTransport.Sender.prototype.send = function(payload) { goog.net.xpc.IframePollingTransport.Receiver = function(transport, windowObj, callback) { - + /** + * The transport to receive from. + * @type {goog.net.xpc.IframePollingTransport} + * @private + */ this.transport_ = transport; this.rcvFrame_ = windowObj; this.cb_ = callback; - this.currentLoc_ = this.rcvFrame_.location.href.split('#')[0] + '#INITIAL'; goog.net.xpc.IframePollingTransport.receivers_.push(this); diff --git a/contexts/data/lib/closure-library/closure/goog/net/xpc/iframepollingtransport_test.html b/contexts/data/lib/closure-library/closure/goog/net/xpc/iframepollingtransport_test.html new file mode 100644 index 0000000..16dda85 --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/net/xpc/iframepollingtransport_test.html @@ -0,0 +1,295 @@ +<!DOCTYPE html> +<html> +<!-- +Copyright 2012 The Closure Library Authors. All Rights Reserved. + +Use of this source code is governed by the Apache License, Version 2.0. +See the COPYING file for details. +--> +<!-- +--> +<head> +<meta http-equiv="X-IframePollingTransport-Compatible" content="IE=edge"> +<title>NativeMessagingTransport Unit-Tests</title> +<script src="../../base.js"></script> +<script> + goog.require('goog.Timer'); + goog.require('goog.dom'); + goog.require('goog.dom.TagName'); + goog.require('goog.functions'); + goog.require('goog.net.xpc'); + goog.require('goog.net.xpc.CrossPageChannel'); + goog.require('goog.net.xpc.CrossPageChannelRole'); + goog.require('goog.object'); + goog.require('goog.testing.MockClock'); + goog.require('goog.testing.jsunit'); + goog.require('goog.testing.recordFunction'); +</script> +<script> + +var mockClock = null; +var outerChannel = null; +var innerChannel = null; + +function setUp() { + mockClock = new goog.testing.MockClock(true /* opt_autoInstall */); + + // Create the peer windows. + var outerPeerHostName = 'https://www.youtube.com'; + var outerPeerWindow = createMockPeerWindow(outerPeerHostName); + + var innerPeerHostName = 'https://www.google.com'; + var innerPeerWindow = createMockPeerWindow(innerPeerHostName); + + // Create the channels. + outerChannel = createChannel(goog.net.xpc.CrossPageChannelRole.OUTER, 'test', + outerPeerHostName, outerPeerWindow, innerPeerHostName, innerPeerWindow); + innerChannel = createChannel(goog.net.xpc.CrossPageChannelRole.INNER, 'test', + innerPeerHostName, innerPeerWindow, outerPeerHostName, outerPeerWindow); +}; + + +function tearDown() { + outerChannel.dispose(); + innerChannel.dispose(); + mockClock.uninstall(); +}; + + +/** Tests that connection happens normally and callbacks are invoked. */ +function testConnect() { + var outerConnectCallback = goog.testing.recordFunction(); + var innerConnectCallback = goog.testing.recordFunction(); + + // Connect the two channels. + outerChannel.connect(outerConnectCallback); + innerChannel.connect(innerConnectCallback); + mockClock.tick(1000); + + // Check that channels were connected and callbacks invoked. + assertEquals(1, outerConnectCallback.getCallCount()); + assertEquals(1, innerConnectCallback.getCallCount()); + assertTrue(outerChannel.isConnected()); + assertTrue(innerChannel.isConnected()); +}; + + +/** Tests that messages are successfully delivered to the inner peer. */ +function testSend_outerToInner() { + var serviceCallback = goog.testing.recordFunction(); + + // Register a service handler in the inner channel. + innerChannel.registerService('svc', function(payload) { + assertEquals('hello', payload); + serviceCallback(); + }); + + // Connect the two channels. + outerChannel.connect(); + innerChannel.connect(); + mockClock.tick(1000); + + // Send a message. + outerChannel.send('svc', 'hello'); + mockClock.tick(1000); + + // Check that the message was handled. + assertEquals(1, serviceCallback.getCallCount()); +}; + + +/** Tests that messages are successfully delivered to the outer peer. */ +function testSend_innerToOuter() { + var serviceCallback = goog.testing.recordFunction(); + + // Register a service handler in the inner channel. + outerChannel.registerService('svc', function(payload) { + assertEquals('hello', payload); + serviceCallback(); + }); + + // Connect the two channels. + outerChannel.connect(); + innerChannel.connect(); + mockClock.tick(1000); + + // Send a message. + innerChannel.send('svc', 'hello'); + mockClock.tick(1000); + + // Check that the message was handled. + assertEquals(1, serviceCallback.getCallCount()); +}; + + +/** Tests that closing the outer peer does not cause an error. */ +function testSend_outerPeerClosed() { + // Connect the inner channel. + innerChannel.connect(); + mockClock.tick(1000); + + // Close the outer peer before it has a chance to connect. + closeWindow(innerChannel.getPeerWindowObject()); + + // Allow timers to execute (and fail). + mockClock.tick(1000); +}; + + +/** Tests that closing the inner peer does not cause an error. */ +function testSend_innerPeerClosed() { + // Connect the outer channel. + outerChannel.connect(); + mockClock.tick(1000); + + // Close the inner peer before it has a chance to connect. + closeWindow(outerChannel.getPeerWindowObject()); + + // Allow timers to execute (and fail). + mockClock.tick(1000); +}; + + +/** Tests that partially closing the outer peer does not cause an error. */ +function testSend_outerPeerClosing() { + // Connect the inner channel. + innerChannel.connect(); + mockClock.tick(1000); + + // Close the outer peer before it has a chance to connect, but + // leave closed set to false to simulate a partially closed window. + closeWindow(innerChannel.getPeerWindowObject()); + innerChannel.getPeerWindowObject().closed = false; + + // Allow timers to execute (and fail). + mockClock.tick(1000); +}; + + +/** Tests that partially closing the inner peer does not cause an error. */ +function testSend_innerPeerClosing() { + // Connect the outer channel. + outerChannel.connect(); + mockClock.tick(1000); + + // Close the inner peer before it has a chance to connect, but + // leave closed set to false to simulate a partially closed window. + closeWindow(outerChannel.getPeerWindowObject()); + outerChannel.getPeerWindowObject().closed = false; + + // Allow timers to execute (and fail). + mockClock.tick(1000); +}; + + +/** + * Creates a channel with the specified configuration, using frame polling. + * @param {!goog.net.xpc.CrossPageChannelRole} role The channel role. + * @param {string} channelName The channel name. + * @param {string} fromHostName The host name of the window hosting the channel. + * @param {!Object} fromWindow The window hosting the channel. + * @param {string} toHostName The host name of the peer window. + * @param {!Object} toWindow The peer window. + */ +function createChannel(role, channelName, fromHostName, fromWindow, toHostName, + toWindow) { + + // Build a channel config using frame polling. + var channelConfig = goog.object.create( + goog.net.xpc.CfgFields.ROLE, + role, + goog.net.xpc.CfgFields.PEER_HOSTNAME, + toHostName, + goog.net.xpc.CfgFields.CHANNEL_NAME, + channelName, + goog.net.xpc.CfgFields.LOCAL_POLL_URI, + fromHostName + '/robots.txt', + goog.net.xpc.CfgFields.PEER_POLL_URI, + toHostName + '/robots.txt', + goog.net.xpc.CfgFields.TRANSPORT, + goog.net.xpc.TransportTypes.IFRAME_POLLING); + + // Build the channel. + var channel = new goog.net.xpc.CrossPageChannel(channelConfig); + channel.setPeerWindowObject(toWindow); + + // Update the transport's getWindow, to return the correct host window. + channel.createTransport_(); + channel.transport_.getWindow = goog.functions.constant(fromWindow); + return channel; +}; + + +/** + * Creates a mock window to use as a peer. The peer window will host the frame + * elements. + * @param {string} url The peer window's initial URL. + */ +function createMockPeerWindow(url) { + var mockPeer = createMockWindow(url); + + // Update the appendChild method to use a mock frame window. + mockPeer.document.body.appendChild = function(el) { + assertEquals(goog.dom.TagName.IFRAME, el.tagName); + mockPeer.frames[el.name] = createMockWindow(el.src); + mockPeer.document.body.element.appendChild(el); + }; + + return mockPeer; +}; + + +/** + * Creates a mock window. + * @param {string} url The window's initial URL. + */ +function createMockWindow(url) { + // Create the mock window, document and body. + var mockWindow = {}; + var mockDocument = {}; + var mockBody = {}; + var mockLocation = {}; + + // Configure the mock window's document body. + mockBody.element = goog.dom.createDom(goog.dom.TagName.BODY); + + // Configure the mock window's document. + mockDocument.body = mockBody; + + // Configure the mock window's location. + mockLocation.href = url; + mockLocation.replace = function(value) { mockLocation.href = value; } + + // Configure the mock window. + mockWindow.document = mockDocument; + mockWindow.frames = {}; + mockWindow.location = mockLocation; + mockWindow.setTimeout = goog.Timer.callOnce; + + return mockWindow; +}; + + +/** + * Emulates closing the specified window by clearing frames, document and + * location. + */ +function closeWindow(targetWindow) { + // Close any child frame windows. + for (var frameName in targetWindow.frames) { + closeWindow(targetWindow.frames[frameName]); + } + + // Clear the target window, set closed to true. + targetWindow.closed = true; + targetWindow.frames = null; + targetWindow.document = null; + targetWindow.location = null; +}; + +</script> +</head> + +<body></body> + +</html> diff --git a/contexts/data/lib/closure-library/closure/goog/net/xpc/iframerelaytransport.js b/contexts/data/lib/closure-library/closure/goog/net/xpc/iframerelaytransport.js index 2f49ad5..1281c49 100644 --- a/contexts/data/lib/closure-library/closure/goog/net/xpc/iframerelaytransport.js +++ b/contexts/data/lib/closure-library/closure/goog/net/xpc/iframerelaytransport.js @@ -56,14 +56,15 @@ goog.net.xpc.IframeRelayTransport = function(channel, opt_domHelper) { * @private */ this.peerRelayUri_ = - this.channel_.cfg_[goog.net.xpc.CfgFields.PEER_RELAY_URI]; + this.channel_.getConfig()[goog.net.xpc.CfgFields.PEER_RELAY_URI]; /** * The id of the iframe the peer page lives in. * @type {string} * @private */ - this.peerIframeId_ = this.channel_.cfg_[goog.net.xpc.CfgFields.IFRAME_ID]; + this.peerIframeId_ = + this.channel_.getConfig()[goog.net.xpc.CfgFields.IFRAME_ID]; if (goog.userAgent.WEBKIT) { goog.net.xpc.IframeRelayTransport.startCleanupTimer_(); @@ -183,13 +184,15 @@ goog.net.xpc.IframeRelayTransport.fragmentMap_ = {}; /** * The transport type. * @type {number} + * @override */ goog.net.xpc.IframeRelayTransport.prototype.transportType = - goog.net.xpc.TransportTypes.IFRAME_RELAY; + goog.net.xpc.TransportTypes.IFRAME_RELAY; /** * Connects this transport. + * @override */ goog.net.xpc.IframeRelayTransport.prototype.connect = function() { if (!this.getWindow()['xpcRelay']) { @@ -248,19 +251,20 @@ goog.net.xpc.IframeRelayTransport.receiveMessage_ = } // We've received all outstanding fragments; combine what we've received - // into payload and fall out to the call to deliver_. + // into payload and fall out to the call to xpcDeliver. payload = fragmentInfo.fragments.join(''); delete goog.net.xpc.IframeRelayTransport.fragmentMap_[messageIdStr]; } - goog.net.xpc.channels_[channelName].deliver_(service, - decodeURIComponent(payload)); + goog.net.xpc.channels[channelName]. + xpcDeliver(service, decodeURIComponent(payload)); }; /** * Handles transport service messages (internal signalling). * @param {string} payload The message content. + * @override */ goog.net.xpc.IframeRelayTransport.prototype.transportServiceHandler = function(payload) { @@ -268,10 +272,10 @@ goog.net.xpc.IframeRelayTransport.prototype.transportServiceHandler = // TODO(user) Safari swallows the SETUP_ACK from the iframe to the // container after hitting reload. this.send(goog.net.xpc.TRANSPORT_SERVICE_, goog.net.xpc.SETUP_ACK_); - this.channel_.notifyConnected_(); + this.channel_.notifyConnected(); } else if (payload == goog.net.xpc.SETUP_ACK_) { - this.channel_.notifyConnected_(); + this.channel_.notifyConnected(); } }; @@ -281,6 +285,7 @@ goog.net.xpc.IframeRelayTransport.prototype.transportServiceHandler = * * @param {string} service Name of service this the message has to be delivered. * @param {string} payload The message content. + * @override */ goog.net.xpc.IframeRelayTransport.prototype.send = function(service, payload) { // If we're on IE and the post-encoding payload is large, split it diff --git a/contexts/data/lib/closure-library/closure/goog/net/xpc/nativemessagingtransport.js b/contexts/data/lib/closure-library/closure/goog/net/xpc/nativemessagingtransport.js index 4458471..e0674fa 100644 --- a/contexts/data/lib/closure-library/closure/goog/net/xpc/nativemessagingtransport.js +++ b/contexts/data/lib/closure-library/closure/goog/net/xpc/nativemessagingtransport.js @@ -21,7 +21,11 @@ goog.provide('goog.net.xpc.NativeMessagingTransport'); +goog.require('goog.Timer'); +goog.require('goog.asserts'); +goog.require('goog.async.Deferred'); goog.require('goog.events'); +goog.require('goog.events.EventHandler'); goog.require('goog.net.xpc'); goog.require('goog.net.xpc.CrossPageChannelRole'); goog.require('goog.net.xpc.Transport'); @@ -40,11 +44,16 @@ goog.require('goog.net.xpc.Transport'); * peer. * @param {goog.dom.DomHelper=} opt_domHelper The dom helper to use for * finding the correct window/document. + * @param {boolean=} opt_oneSidedHandshake If this is true, only the outer + * transport sends a SETUP message and expects a SETUP_ACK. The inner + * transport goes connected when it receives the SETUP. + * @param {number=} opt_protocolVersion Which version of its setup protocol the + * transport should use. The default is '2'. * @constructor * @extends {goog.net.xpc.Transport} */ goog.net.xpc.NativeMessagingTransport = function(channel, peerHostname, - opt_domHelper) { + opt_domHelper, opt_oneSidedHandshake, opt_protocolVersion) { goog.base(this, opt_domHelper); /** @@ -55,17 +64,135 @@ goog.net.xpc.NativeMessagingTransport = function(channel, peerHostname, this.channel_ = channel; /** + * Which version of the transport's protocol should be used. + * @type {number} + * @private + */ + this.protocolVersion_ = opt_protocolVersion || 2; + goog.asserts.assert(this.protocolVersion_ >= 1); + goog.asserts.assert(this.protocolVersion_ <= 2); + + /** * The hostname of the peer. This parameterizes all calls to postMessage, and * should contain the precise protocol, domain, and port of the peer window. * @type {string} * @private */ this.peerHostname_ = peerHostname || '*'; + + /** + * The event handler. + * @type {!goog.events.EventHandler} + * @private + */ + this.eventHandler_ = new goog.events.EventHandler(this); + + /** + * Timer for connection reattempts. + * @type {!goog.Timer} + * @private + */ + this.maybeAttemptToConnectTimer_ = new goog.Timer(100, this.getWindow()); + + /** + * Whether one-sided handshakes are enabled. + * @type {boolean} + * @private + */ + this.oneSidedHandshake_ = !!opt_oneSidedHandshake; + + /** + * Fires once we've received our SETUP_ACK message. + * @type {!goog.async.Deferred} + * @private + */ + this.setupAckReceived_ = new goog.async.Deferred(); + + /** + * Fires once we've sent our SETUP_ACK message. + * @type {!goog.async.Deferred} + * @private + */ + this.setupAckSent_ = new goog.async.Deferred(); + + /** + * Fires once we're marked connected. + * @type {!goog.async.Deferred} + * @private + */ + this.connected_ = new goog.async.Deferred(); + + /** + * The unique ID of this side of the connection. Used to determine when a peer + * is reloaded. + * @type {string} + * @private + */ + this.endpointId_ = goog.net.xpc.getRandomString(10); + + /** + * The unique ID of the peer. If we get a message from a peer with an ID we + * don't expect, we reset the connection. + * @type {?string} + * @private + */ + this.peerEndpointId_ = null; + + // We don't want to mark ourselves connected until we have sent whatever + // message will cause our counterpart in the other frame to also declare + // itself connected, if there is such a message. Otherwise we risk a user + // message being sent in advance of that message, and it being discarded. + if (this.oneSidedHandshake_) { + if (this.channel_.getRole() == goog.net.xpc.CrossPageChannelRole.INNER) { + // One sided handshake, inner frame: + // SETUP_ACK must be received. + this.connected_.awaitDeferred(this.setupAckReceived_); + } else { + // One sided handshake, outer frame: + // SETUP_ACK must be sent. + this.connected_.awaitDeferred(this.setupAckSent_); + } + } else { + // Two sided handshake: + // SETUP_ACK has to have been received, and sent. + this.connected_.awaitDeferred(this.setupAckReceived_); + if (this.protocolVersion_ == 2) { + this.connected_.awaitDeferred(this.setupAckSent_); + } + } + this.connected_.addCallback(this.notifyConnected_, this); + this.connected_.callback(true); + + this.eventHandler_. + listen(this.maybeAttemptToConnectTimer_, goog.Timer.TICK, + this.maybeAttemptToConnect_); + + goog.net.xpc.logger.info('NativeMessagingTransport created. ' + + 'protocolVersion=' + this.protocolVersion_ + ', oneSidedHandshake=' + + this.oneSidedHandshake_ + ', role=' + this.channel_.getRole()); }; goog.inherits(goog.net.xpc.NativeMessagingTransport, goog.net.xpc.Transport); /** + * Length of the delay in milliseconds between the channel being connected and + * the connection callback being called, in cases where coverage of timing flaws + * is required. + * @type {number} + * @private + */ +goog.net.xpc.NativeMessagingTransport.CONNECTION_DELAY_MS_ = 200; + + +/** + * Current determination of peer's protocol version, or null for unknown. + * @type {?number} + * @private + */ +goog.net.xpc.NativeMessagingTransport.prototype.peerProtocolVersion_ = null; + + +/** * Flag indicating if this instance of the transport has been initialized. * @type {boolean} * @private @@ -76,12 +203,21 @@ goog.net.xpc.NativeMessagingTransport.prototype.initialized_ = false; /** * The transport type. * @type {number} + * @override */ goog.net.xpc.NativeMessagingTransport.prototype.transportType = goog.net.xpc.TransportTypes.NATIVE_MESSAGING; /** + * The delimiter used for transport service messages. + * @type {string} + * @private + */ +goog.net.xpc.NativeMessagingTransport.MESSAGE_DELIMITER_ = ','; + + +/** * Tracks the number of NativeMessagingTransport channels that have been * initialized but not disposed yet in a map keyed by the UID of the window * object. This allows for multiple windows to be initiallized and listening @@ -93,6 +229,28 @@ goog.net.xpc.NativeMessagingTransport.activeCount_ = {}; /** + * Id of a timer user during postMessage sends. + * @type {number} + * @private + */ +goog.net.xpc.NativeMessagingTransport.sendTimerId_ = 0; + + +/** + * Checks whether the peer transport protocol version could be as indicated. + * @param {number} version The version to check for. + * @return {boolean} Whether the peer transport protocol version is as + * indicated, or null. + * @private + */ +goog.net.xpc.NativeMessagingTransport.prototype.couldPeerVersionBe_ = + function(version) { + return this.peerProtocolVersion_ == null || + this.peerProtocolVersion_ == version; +}; + + +/** * Initializes this transport. Registers a listener for 'message'-events * on the document. * @param {Window} listenWindow The window to listen to events on. @@ -153,19 +311,23 @@ goog.net.xpc.NativeMessagingTransport.messageReceived_ = function(msgEvt) { // - channel was created in a different namespace // - message was sent to the wrong window // - channel has become stale (e.g. caching iframes and back clicks) - var channel = goog.net.xpc.channels_[channelName]; + var channel = goog.net.xpc.channels[channelName]; if (channel) { - channel.deliver_(service, payload, msgEvt.getBrowserEvent().origin); + channel.xpcDeliver(service, payload, msgEvt.getBrowserEvent().origin); return true; } + var transportMessageType = + goog.net.xpc.NativeMessagingTransport.parseTransportPayload_(payload)[0]; + // Check if there are any stale channel names that can be updated. - for (var staleChannelName in goog.net.xpc.channels_) { - var staleChannel = goog.net.xpc.channels_[staleChannelName]; + for (var staleChannelName in goog.net.xpc.channels) { + var staleChannel = goog.net.xpc.channels[staleChannelName]; if (staleChannel.getRole() == goog.net.xpc.CrossPageChannelRole.INNER && !staleChannel.isConnected() && service == goog.net.xpc.TRANSPORT_SERVICE_ && - payload == goog.net.xpc.SETUP) { + (transportMessageType == goog.net.xpc.SETUP || + transportMessageType == goog.net.xpc.SETUP_NTPV2)) { // Inner peer received SETUP message but channel names did not match. // Start using the channel name sent from outer peer. The channel name // of the inner peer can easily become out of date, as iframe's and their @@ -176,10 +338,10 @@ goog.net.xpc.NativeMessagingTransport.messageReceived_ = function(msgEvt) { goog.net.xpc.logger.fine('changing channel name to ' + channelName); staleChannel.name = channelName; // Remove old stale pointer to channel. - delete goog.net.xpc.channels_[staleChannelName]; + delete goog.net.xpc.channels[staleChannelName]; // Create fresh pointer to channel. - goog.net.xpc.channels_[channelName] = staleChannel; - staleChannel.deliver_(service, payload); + goog.net.xpc.channels[channelName] = staleChannel; + staleChannel.xpcDeliver(service, payload); return true; } } @@ -193,27 +355,135 @@ goog.net.xpc.NativeMessagingTransport.messageReceived_ = function(msgEvt) { /** * Handles transport service messages. * @param {string} payload The message content. + * @override */ goog.net.xpc.NativeMessagingTransport.prototype.transportServiceHandler = function(payload) { - switch (payload) { + var transportParts = + goog.net.xpc.NativeMessagingTransport.parseTransportPayload_(payload); + var transportMessageType = transportParts[0]; + var peerEndpointId = transportParts[1]; + switch (transportMessageType) { + case goog.net.xpc.SETUP_ACK_: + this.setPeerProtocolVersion_(1); + if (!this.setupAckReceived_.hasFired()) { + this.setupAckReceived_.callback(true); + } + break; + case goog.net.xpc.SETUP_ACK_NTPV2: + if (this.protocolVersion_ == 2) { + this.setPeerProtocolVersion_(2); + if (!this.setupAckReceived_.hasFired()) { + this.setupAckReceived_.callback(true); + } + } + break; case goog.net.xpc.SETUP: - this.send(goog.net.xpc.TRANSPORT_SERVICE_, goog.net.xpc.SETUP_ACK_); + this.setPeerProtocolVersion_(1); + this.sendSetupAckMessage_(1); break; - case goog.net.xpc.SETUP_ACK_: - this.channel_.notifyConnected_(); + case goog.net.xpc.SETUP_NTPV2: + if (this.protocolVersion_ == 2) { + var prevPeerProtocolVersion = this.peerProtocolVersion_; + this.setPeerProtocolVersion_(2); + this.sendSetupAckMessage_(2); + if ((prevPeerProtocolVersion == 1 || this.peerEndpointId_ != null) && + this.peerEndpointId_ != peerEndpointId) { + // Send a new SETUP message since the peer has been replaced. + goog.net.xpc.logger.info('Sending SETUP and changing peer ID to: ' + + peerEndpointId); + this.sendSetupMessage_(); + } + this.peerEndpointId_ = peerEndpointId; + } break; } }; /** + * Sends a SETUP transport service message of the correct protocol number for + * our current situation. + * @private + */ +goog.net.xpc.NativeMessagingTransport.prototype.sendSetupMessage_ = + function() { + // 'real' (legacy) v1 transports don't know about there being v2 ones out + // there, and we shouldn't either. + goog.asserts.assert(!(this.protocolVersion_ == 1 && + this.peerProtocolVersion_ == 2)); + + if (this.protocolVersion_ == 2 && this.couldPeerVersionBe_(2)) { + var payload = goog.net.xpc.SETUP_NTPV2; + payload += goog.net.xpc.NativeMessagingTransport.MESSAGE_DELIMITER_; + payload += this.endpointId_; + this.send(goog.net.xpc.TRANSPORT_SERVICE_, payload); + } + + // For backward compatibility reasons, the V1 SETUP message can be sent by + // both V1 and V2 transports. Once a V2 transport has 'heard' another V2 + // transport it starts ignoring V1 messages, so the V2 message must be sent + // first. + if (this.couldPeerVersionBe_(1)) { + this.send(goog.net.xpc.TRANSPORT_SERVICE_, goog.net.xpc.SETUP); + } +}; + + +/** + * Sends a SETUP_ACK transport service message of the correct protocol number + * for our current situation. + * @param {number} protocolVersion The protocol version of the SETUP message + * which gave rise to this ack message. + * @private + */ +goog.net.xpc.NativeMessagingTransport.prototype.sendSetupAckMessage_ = + function(protocolVersion) { + goog.asserts.assert(this.protocolVersion_ != 1 || protocolVersion != 2, + 'Shouldn\'t try to send a v2 setup ack in v1 mode.'); + if (this.protocolVersion_ == 2 && this.couldPeerVersionBe_(2) && + protocolVersion == 2) { + this.send(goog.net.xpc.TRANSPORT_SERVICE_, goog.net.xpc.SETUP_ACK_NTPV2); + } else if (this.couldPeerVersionBe_(1) && protocolVersion == 1) { + this.send(goog.net.xpc.TRANSPORT_SERVICE_, goog.net.xpc.SETUP_ACK_); + } else { + return; + } + + if (!this.setupAckSent_.hasFired()) { + this.setupAckSent_.callback(true); + } +}; + + +/** + * Attempts to set the peer protocol number. Downgrades from 2 to 1 are not + * permitted. + * @param {number} version The new protocol number. + * @private + */ +goog.net.xpc.NativeMessagingTransport.prototype.setPeerProtocolVersion_ = + function(version) { + if (version > this.peerProtocolVersion_) { + this.peerProtocolVersion_ = version; + } + if (this.peerProtocolVersion_ == 1) { + if (!this.setupAckSent_.hasFired() && !this.oneSidedHandshake_) { + this.setupAckSent_.callback(true); + } + this.peerEndpointId_ = null; + } +}; + + +/** * Connects this transport. + * @override */ goog.net.xpc.NativeMessagingTransport.prototype.connect = function() { goog.net.xpc.NativeMessagingTransport.initialize_(this.getWindow()); this.initialized_ = true; - this.connectWithRetries_(); + this.maybeAttemptToConnect_(); }; @@ -226,13 +496,20 @@ goog.net.xpc.NativeMessagingTransport.prototype.connect = function() { * soft-reloads and history navigations. * @private */ -goog.net.xpc.NativeMessagingTransport.prototype.connectWithRetries_ = +goog.net.xpc.NativeMessagingTransport.prototype.maybeAttemptToConnect_ = function() { - if (this.channel_.isConnected() || this.isDisposed()) { + // In a one-sided handshake, the outer frame does not send a SETUP message, + // but the inner frame does. + var outerFrame = this.channel_.getRole() == + goog.net.xpc.CrossPageChannelRole.OUTER; + if ((this.oneSidedHandshake_ && outerFrame) || + this.channel_.isConnected() || + this.isDisposed()) { + this.maybeAttemptToConnectTimer_.stop(); return; } - this.send(goog.net.xpc.TRANSPORT_SERVICE_, goog.net.xpc.SETUP); - this.getWindow().setTimeout(goog.bind(this.connectWithRetries_, this), 100); + this.maybeAttemptToConnectTimer_.start(); + this.sendSetupMessage_(); }; @@ -241,31 +518,74 @@ goog.net.xpc.NativeMessagingTransport.prototype.connectWithRetries_ = * @param {string} service The name off the service the message is to be * delivered to. * @param {string} payload The message content. + * @override */ goog.net.xpc.NativeMessagingTransport.prototype.send = function(service, payload) { - var win = this.channel_.peerWindowObject_; + var win = this.channel_.getPeerWindowObject(); if (!win) { goog.net.xpc.logger.fine('send(): window not ready'); return; } - // postMessage is a method of the window object, except in some versions of - // Opera, where it is a method of the document object. - var obj = win.postMessage ? win : win.document; this.send = function(service, payload) { - goog.net.xpc.logger.fine('send(): payload=' + payload + - ' to hostname=' + this.peerHostname_); - obj.postMessage(this.channel_.name + '|' + service + ':' + payload, - this.peerHostname_); + // In IE8 (and perhaps elsewhere), it seems like postMessage is sometimes + // implemented as a synchronous call. That is, calling it synchronously + // calls whatever listeners it has, and control is not returned to the + // calling thread until those listeners are run. This produces different + // ordering to all other browsers, and breaks this protocol. This timer + // callback is introduced to produce standard behavior across all browsers. + var transport = this; + var channelName = this.channel_.name; + var sendFunctor = function() { + transport.sendTimerId_ = 0; + + try { + // postMessage is a method of the window object, except in some + // versions of Opera, where it is a method of the document object. It + // also seems that the appearance of postMessage on the peer window + // object can sometimes be delayed. + var obj = win.postMessage ? win : win.document; + if (!obj.postMessage) { + goog.net.xpc.logger.warning('Peer window had no postMessage ' + + 'function.'); + return; + } + + obj.postMessage(channelName + '|' + service + ':' + payload, + transport.peerHostname_); + goog.net.xpc.logger.fine('send(): service=' + service + ' payload=' + + payload + ' to hostname=' + transport.peerHostname_); + } catch (error) { + // There is some evidence (not totally convincing) that postMessage can + // be missing or throw errors during a narrow timing window during + // startup. This protects against that. + goog.net.xpc.logger.warning('Error performing postMessage, ignoring.', + error); + } + }; + this.sendTimerId_ = goog.Timer.callOnce(sendFunctor, 0); }; this.send(service, payload); }; +/** + * Notify the channel that this transport is connected. If either transport is + * protocol v1, a short delay is required to paper over timing vulnerabilities + * in that protocol version. + * @private + */ +goog.net.xpc.NativeMessagingTransport.prototype.notifyConnected_ = + function() { + var delay = (this.protocolVersion_ == 1 || this.peerProtocolVersion_ == 1) ? + goog.net.xpc.NativeMessagingTransport.CONNECTION_DELAY_MS_ : undefined; + this.channel_.notifyConnected(delay); +}; + + /** @override */ goog.net.xpc.NativeMessagingTransport.prototype.disposeInternal = function() { - goog.base(this, 'disposeInternal'); if (this.initialized_) { var listenWindow = this.getWindow(); var uid = goog.getUid(listenWindow); @@ -280,8 +600,48 @@ goog.net.xpc.NativeMessagingTransport.prototype.disposeInternal = function() { goog.net.xpc.NativeMessagingTransport); } } + + if (this.sendTimerId_) { + goog.Timer.clear(this.sendTimerId_); + this.sendTimerId_ = 0; + } + + goog.dispose(this.eventHandler_); + delete this.eventHandler_; + + goog.dispose(this.maybeAttemptToConnectTimer_); + delete this.maybeAttemptToConnectTimer_; + + this.setupAckReceived_.cancel(); + delete this.setupAckReceived_; + this.setupAckSent_.cancel(); + delete this.setupAckSent_; + this.connected_.cancel(); + delete this.connected_; + // Cleaning up this.send as it is an instance method, created in // goog.net.xpc.NativeMessagingTransport.prototype.send and has a closure over // this.channel_.peerWindowObject_. delete this.send; + + goog.base(this, 'disposeInternal'); +}; + + +/** + * Parse a transport service payload message. For v1, it is simply expected to + * be 'SETUP' or 'SETUP_ACK'. For v2, an example setup message is + * 'SETUP_NTPV2,abc123', where the second part is the endpoint id. The v2 setup + * ack message is simply 'SETUP_ACK_NTPV2'. + * @param {string} payload The payload. + * @return {!Array.<?string>} An array with the message type as the first member + * and the endpoint id as the second, if one was sent, or null otherwise. + * @private + */ +goog.net.xpc.NativeMessagingTransport.parseTransportPayload_ = + function(payload) { + var transportParts = (/** @type {!Array.<?string>} */ payload.split( + goog.net.xpc.NativeMessagingTransport.MESSAGE_DELIMITER_)); + transportParts[1] = transportParts[1] || null; + return transportParts; }; diff --git a/contexts/data/lib/closure-library/closure/goog/net/xpc/nativemessagingtransport_test.html b/contexts/data/lib/closure-library/closure/goog/net/xpc/nativemessagingtransport_test.html index a18cb2a..8e2086c 100644 --- a/contexts/data/lib/closure-library/closure/goog/net/xpc/nativemessagingtransport_test.html +++ b/contexts/data/lib/closure-library/closure/goog/net/xpc/nativemessagingtransport_test.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <!-- --> <html> @@ -10,15 +11,20 @@ See the COPYING file for details. <head> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>NativeMessagingTransport Unit-Tests</title> -<script src="../../base.js"></script> -<script> +<script src="../../base.js" type="text/javascript"></script> +<script type="text/javascript"> goog.require('goog.net.xpc.CrossPageChannel'); goog.require('goog.net.xpc.CrossPageChannelRole'); goog.require('goog.net.xpc.NativeMessagingTransport'); goog.require('goog.testing.events'); goog.require('goog.testing.jsunit'); </script> -<script> +<script type="text/javascript"> + +// This test only tests the native messaing transport protocol version 2. +// Testing of previous versions and of backward/forward compatibility is done +// in crosspagechannel_test.html. + function tearDown() { goog.net.xpc.NativeMessagingTransport.activeCount_ = {}; @@ -27,21 +33,32 @@ function tearDown() { function testConstructor() { - var t = new goog.net.xpc.NativeMessagingTransport(null, 'http://g.com:80'); + var xpc = getTestChannel(); + + var t = new goog.net.xpc.NativeMessagingTransport(xpc, 'http://g.com:80', + undefined /* opt_domHelper */, false /* opt_oneSidedHandshake */, + 2 /* opt_protocolVersion */); assertEquals('http://g.com:80', t.peerHostname_); - var t = new goog.net.xpc.NativeMessagingTransport(null, null); + var t = new goog.net.xpc.NativeMessagingTransport(xpc, + null /* peerHostName */, undefined /* opt_domHelper */, + false /* opt_oneSidedHandshake */, 2 /* opt_protocolVersion */); assertEquals('*', t.peerHostname_); t.dispose(); } function testConstructorDom() { + var xpc = getTestChannel(); + var t = new goog.net.xpc.NativeMessagingTransport( - null, 'http://g.com:80', goog.dom.getDomHelper()); + xpc, 'http://g.com:80', goog.dom.getDomHelper(), + false /* opt_oneSidedHandshake */, 2 /* opt_protocolVersion */); assertEquals('http://g.com:80', t.peerHostname_); - var t = new goog.net.xpc.NativeMessagingTransport(null, null); + var t = new goog.net.xpc.NativeMessagingTransport(xpc, + null /* peerHostName */, false /* opt_oneSidedHandshake */, + 2 /* opt_protocolVersion */); assertEquals('*', t.peerHostname_); t.dispose(); } @@ -51,18 +68,26 @@ function testDispose() { var xpc = getTestChannel(); var listenedObj = window.postMessage ? window : document; - var t0 = new goog.net.xpc.NativeMessagingTransport(xpc, null); + var t0 = new goog.net.xpc.NativeMessagingTransport(xpc, + null /* peerHostName */, false /* opt_oneSidedHandshake */, + 2 /* opt_protocolVersion */); assertEquals(0, goog.events.removeAll(listenedObj, 'message')); t0.dispose(); assertEquals(0, goog.events.removeAll(listenedObj, 'message')); - var t1 = new goog.net.xpc.NativeMessagingTransport(xpc, null); + var t1 = new goog.net.xpc.NativeMessagingTransport(xpc, + null /* peerHostName */, false /* opt_oneSidedHandshake */, + 2 /* opt_protocolVersion */); t1.connect(); t1.dispose(); assertEquals(0, goog.events.removeAll(listenedObj, 'message')); - var t2 = new goog.net.xpc.NativeMessagingTransport(xpc, null); - var t3 = new goog.net.xpc.NativeMessagingTransport(xpc, null); + var t2 = new goog.net.xpc.NativeMessagingTransport(xpc, + null /* peerHostName */, false /* opt_oneSidedHandshake */, + 2 /* opt_protocolVersion */); + var t3 = new goog.net.xpc.NativeMessagingTransport(xpc, + null /* peerHostName */, false /* opt_oneSidedHandshake */, + 2 /* opt_protocolVersion */); t2.connect(); t3.connect(); t2.dispose(); @@ -74,18 +99,26 @@ function testDisposeWithDom() { var xpc = getTestChannel(goog.dom.getDomHelper()); var listenedObj = window.postMessage ? window : document; - var t0 = new goog.net.xpc.NativeMessagingTransport(xpc, null); + var t0 = new goog.net.xpc.NativeMessagingTransport(xpc, + null /* peerHostName */, false /* opt_oneSidedHandshake */, + 2 /* opt_protocolVersion */); assertEquals(0, goog.events.removeAll(listenedObj, 'message')); t0.dispose(); assertEquals(0, goog.events.removeAll(listenedObj, 'message')); - var t1 = new goog.net.xpc.NativeMessagingTransport(xpc, null); + var t1 = new goog.net.xpc.NativeMessagingTransport(xpc, + null /* peerHostName */, false /* opt_oneSidedHandshake */, + 2 /* opt_protocolVersion */); t1.connect(); t1.dispose(); assertEquals(0, goog.events.removeAll(listenedObj, 'message')); - var t2 = new goog.net.xpc.NativeMessagingTransport(xpc, null); - var t3 = new goog.net.xpc.NativeMessagingTransport(xpc, null); + var t2 = new goog.net.xpc.NativeMessagingTransport(xpc, + null /* peerHostName */, false /* opt_oneSidedHandshake */, + 2 /* opt_protocolVersion */); + var t3 = new goog.net.xpc.NativeMessagingTransport(xpc, + null /* peerHostName */, false /* opt_oneSidedHandshake */, + 2 /* opt_protocolVersion */); t2.connect(); t3.connect(); t2.dispose(); @@ -109,7 +142,7 @@ function testSendingMessagesToUnconnectedInnerPeer() { var xpc = getTestChannel(); var serviceResult, payloadResult; - xpc.deliver_ = function(service, payload) { + xpc.xpcDeliver = function(service, payload) { serviceResult = service; payloadResult = payload; }; @@ -121,7 +154,8 @@ function testSendingMessagesToUnconnectedInnerPeer() { xpc.isConnected = function() { return false; }; - var t = new goog.net.xpc.NativeMessagingTransport(xpc, 'http://g.com'); + var t = new goog.net.xpc.NativeMessagingTransport(xpc, 'http://g.com', + false /* opt_oneSidedHandshake */, 2 /* opt_protocolVersion */); // Test a valid message. var e = createMockEvent('test_channel|test_service:test_payload'); @@ -144,6 +178,109 @@ function testSendingMessagesToUnconnectedInnerPeer() { } +function testSignalConnected_innerFrame() { + checkSignalConnected(false /* oneSidedHandshake */, + true /* innerFrame */); +} + + +function testSignalConnected_outerFrame() { + checkSignalConnected(false /* oneSidedHandshake */, + false /* innerFrame */); +} + + +function testSignalConnected_singleSided_innerFrame() { + checkSignalConnected(true /* oneSidedHandshake */, + true /* innerFrame */); +} + + +function testSignalConnected_singleSided_outerFrame() { + checkSignalConnected(true /* oneSidedHandshake */, + false /* innerFrame */); +} + + +function checkSignalConnected(oneSidedHandshake, innerFrame, + peerProtocolVersion, protocolVersion) { + var xpc = getTestChannel(); + var connected = false; + xpc.notifyConnected = function() { + if (connected) { + fail(); + } else { + connected = true; + } + }; + xpc.getRole = function() { + return innerFrame ? goog.net.xpc.CrossPageChannelRole.INNER : + goog.net.xpc.CrossPageChannelRole.OUTER; + }; + xpc.isConnected = function() { + return false; + }; + + var transport = new goog.net.xpc.NativeMessagingTransport(xpc, 'http://g.com', + undefined /* opt_domHelper */, + oneSidedHandshake /* opt_oneSidedHandshake */, + 2 /* protocolVerion */); + var sentPayloads = []; + transport.send = function(service, payload) { + assertEquals(goog.net.xpc.TRANSPORT_SERVICE_, service); + sentPayloads.push(payload); + } + function assertSent(payloads) { + assertArrayEquals(payloads, sentPayloads); + sentPayloads = []; + } + var endpointId = transport.endpointId_; + var peerEndpointId1 = 'abc123'; + var peerEndpointId2 = 'def234'; + + assertFalse(connected); + if (!oneSidedHandshake || innerFrame) { + transport.transportServiceHandler(goog.net.xpc.SETUP_NTPV2 + ',' + + peerEndpointId1); + transport.transportServiceHandler(goog.net.xpc.SETUP); + assertSent([goog.net.xpc.SETUP_ACK_NTPV2]); + assertFalse(connected); + transport.transportServiceHandler(goog.net.xpc.SETUP_ACK_NTPV2); + assertSent([]); + assertTrue(connected); + } else { + transport.transportServiceHandler(goog.net.xpc.SETUP_ACK_NTPV2); + assertSent([]); + assertFalse(connected); + transport.transportServiceHandler(goog.net.xpc.SETUP_NTPV2 + ',' + + peerEndpointId1); + transport.transportServiceHandler(goog.net.xpc.SETUP); + assertSent([goog.net.xpc.SETUP_ACK_NTPV2]); + assertTrue(connected); + } + + // Verify that additional transport service traffic doesn't cause duplicate + // notifications. + transport.transportServiceHandler(goog.net.xpc.SETUP_NTPV2 + ',' + + peerEndpointId1); + transport.transportServiceHandler(goog.net.xpc.SETUP); + assertSent([goog.net.xpc.SETUP_ACK_NTPV2]); + transport.transportServiceHandler(goog.net.xpc.SETUP_ACK_NTPV2); + assertSent([]); + + // Simulate a reconnection by sending a SETUP message from a frame with a + // different endpoint id. No further connection callbacks should fire, but + // a new SETUP message should be triggered. + transport.transportServiceHandler(goog.net.xpc.SETUP_NTPV2 + ',' + + peerEndpointId2); + transport.transportServiceHandler(goog.net.xpc.SETUP); + assertSent([goog.net.xpc.SETUP_ACK_NTPV2, goog.net.xpc.SETUP_NTPV2 + ',' + + endpointId]); + transport.transportServiceHandler(goog.net.xpc.SETUP_ACK_NTPV2); + assertSent([]); +} + + function createMockEvent(data) { var event = {}; event.getBrowserEvent = function() { return {data: data} }; @@ -154,7 +291,9 @@ function createMockEvent(data) { function getTestChannel(opt_domHelper) { var cfg = {}; cfg[goog.net.xpc.CfgFields.CHANNEL_NAME] = 'test_channel'; - return new goog.net.xpc.CrossPageChannel(cfg, opt_domHelper); + return new goog.net.xpc.CrossPageChannel(cfg, opt_domHelper, + undefined /* opt_domHelper */, false /* opt_oneSidedHandshake */, + 2 /* opt_protocolVersion */); } </script> diff --git a/contexts/data/lib/closure-library/closure/goog/net/xpc/nixtransport.js b/contexts/data/lib/closure-library/closure/goog/net/xpc/nixtransport.js index d3b0dd7..7e00b7b 100644 --- a/contexts/data/lib/closure-library/closure/goog/net/xpc/nixtransport.js +++ b/contexts/data/lib/closure-library/closure/goog/net/xpc/nixtransport.js @@ -39,6 +39,7 @@ goog.require('goog.net.xpc.Transport'); goog.require('goog.reflect'); + /** * NIX method transport. * @@ -153,7 +154,7 @@ goog.net.xpc.NixTransport.isNixSupported = function() { window.opener = /** @type {Window} */ ({}); isSupported = goog.reflect.canAccessProperty(window, 'opener'); window.opener = oldOpener; - } catch(e) { } + } catch (e) { } return isSupported; }; @@ -165,6 +166,7 @@ goog.net.xpc.NixTransport.isNixSupported = function() { * Note that this method can be called multiple times, as * it internally checks whether the work is necessary before * proceeding. + * @param {Window} listenWindow The window containing the affected page. * @private */ goog.net.xpc.NixTransport.conductGlobalSetup_ = function(listenWindow) { @@ -174,79 +176,79 @@ goog.net.xpc.NixTransport.conductGlobalSetup_ = function(listenWindow) { // Inject the VBScript code needed. var vbscript = - // We create a class to act as a wrapper for - // a Javascript call, to prevent a break in of - // the context. - 'Class ' + goog.net.xpc.NixTransport.NIX_WRAPPER + '\n ' + - - // An internal member for keeping track of the - // transport for which this wrapper exists. - 'Private m_Transport\n' + - - // An internal member for keeping track of the - // auth token associated with the context that - // created this wrapper. Used for validation - // purposes. - 'Private m_Auth\n' + - - // Method for internally setting the value - // of the m_Transport property. We have the - // isEmpty check to prevent the transport - // from being overridden with an illicit - // object by a malicious party. - 'Public Sub SetTransport(transport)\n' + - 'If isEmpty(m_Transport) Then\n' + - 'Set m_Transport = transport\n' + - 'End If\n' + - 'End Sub\n' + - - // Method for internally setting the value - // of the m_Auth property. We have the - // isEmpty check to prevent the transport - // from being overridden with an illicit - // object by a malicious party. - 'Public Sub SetAuth(auth)\n' + - 'If isEmpty(m_Auth) Then\n' + - 'm_Auth = auth\n' + - 'End If\n' + - 'End Sub\n' + - - // Returns the auth token to the gadget, so it can - // confirm a match before initiating the connection - 'Public Function GetAuthToken()\n ' + - 'GetAuthToken = m_Auth\n' + - 'End Function\n' + - - // A wrapper method which causes a - // message to be sent to the other context. - 'Public Sub SendMessage(service, payload)\n ' + - 'Call m_Transport.' + - goog.net.xpc.NixTransport.NIX_HANDLE_MESSAGE + '(service, payload)\n' + - 'End Sub\n' + - - // Method for setting up the inner->outer - // channel. - 'Public Sub CreateChannel(channel)\n ' + - 'Call m_Transport.' + - goog.net.xpc.NixTransport.NIX_CREATE_CHANNEL + '(channel)\n' + - 'End Sub\n' + - - // An empty field with a unique identifier to - // prevent the code from confusing this wrapper - // with a run-of-the-mill value found in window.opener. - 'Public Sub ' + goog.net.xpc.NixTransport.NIX_ID_FIELD + '()\n ' + - 'End Sub\n' + - 'End Class\n ' + - - // Function to get a reference to the wrapper. - 'Function ' + - goog.net.xpc.NixTransport.NIX_GET_WRAPPER + '(transport, auth)\n' + - 'Dim wrap\n' + - 'Set wrap = New ' + goog.net.xpc.NixTransport.NIX_WRAPPER + '\n' + - 'wrap.SetTransport transport\n' + - 'wrap.SetAuth auth\n' + - 'Set ' + goog.net.xpc.NixTransport.NIX_GET_WRAPPER + ' = wrap\n' + - 'End Function'; + // We create a class to act as a wrapper for + // a Javascript call, to prevent a break in of + // the context. + 'Class ' + goog.net.xpc.NixTransport.NIX_WRAPPER + '\n ' + + + // An internal member for keeping track of the + // transport for which this wrapper exists. + 'Private m_Transport\n' + + + // An internal member for keeping track of the + // auth token associated with the context that + // created this wrapper. Used for validation + // purposes. + 'Private m_Auth\n' + + + // Method for internally setting the value + // of the m_Transport property. We have the + // isEmpty check to prevent the transport + // from being overridden with an illicit + // object by a malicious party. + 'Public Sub SetTransport(transport)\n' + + 'If isEmpty(m_Transport) Then\n' + + 'Set m_Transport = transport\n' + + 'End If\n' + + 'End Sub\n' + + + // Method for internally setting the value + // of the m_Auth property. We have the + // isEmpty check to prevent the transport + // from being overridden with an illicit + // object by a malicious party. + 'Public Sub SetAuth(auth)\n' + + 'If isEmpty(m_Auth) Then\n' + + 'm_Auth = auth\n' + + 'End If\n' + + 'End Sub\n' + + + // Returns the auth token to the gadget, so it can + // confirm a match before initiating the connection + 'Public Function GetAuthToken()\n ' + + 'GetAuthToken = m_Auth\n' + + 'End Function\n' + + + // A wrapper method which causes a + // message to be sent to the other context. + 'Public Sub SendMessage(service, payload)\n ' + + 'Call m_Transport.' + + goog.net.xpc.NixTransport.NIX_HANDLE_MESSAGE + '(service, payload)\n' + + 'End Sub\n' + + + // Method for setting up the inner->outer + // channel. + 'Public Sub CreateChannel(channel)\n ' + + 'Call m_Transport.' + + goog.net.xpc.NixTransport.NIX_CREATE_CHANNEL + '(channel)\n' + + 'End Sub\n' + + + // An empty field with a unique identifier to + // prevent the code from confusing this wrapper + // with a run-of-the-mill value found in window.opener. + 'Public Sub ' + goog.net.xpc.NixTransport.NIX_ID_FIELD + '()\n ' + + 'End Sub\n' + + 'End Class\n ' + + + // Function to get a reference to the wrapper. + 'Function ' + + goog.net.xpc.NixTransport.NIX_GET_WRAPPER + '(transport, auth)\n' + + 'Dim wrap\n' + + 'Set wrap = New ' + goog.net.xpc.NixTransport.NIX_WRAPPER + '\n' + + 'wrap.SetTransport transport\n' + + 'wrap.SetAuth auth\n' + + 'Set ' + goog.net.xpc.NixTransport.NIX_GET_WRAPPER + ' = wrap\n' + + 'End Function'; try { listenWindow.execScript(vbscript, 'vbscript'); @@ -263,9 +265,10 @@ goog.net.xpc.NixTransport.conductGlobalSetup_ = function(listenWindow) { * The transport type. * @type {number} * @protected + * @override */ goog.net.xpc.NixTransport.prototype.transportType = - goog.net.xpc.TransportTypes.NIX; + goog.net.xpc.TransportTypes.NIX; /** @@ -292,6 +295,7 @@ goog.net.xpc.NixTransport.prototype.nixChannel_ = null; /** * Connect this transport. + * @override */ goog.net.xpc.NixTransport.prototype.connect = function() { if (this.channel_.getRole() == goog.net.xpc.CrossPageChannelRole.OUTER) { @@ -319,14 +323,14 @@ goog.net.xpc.NixTransport.prototype.attemptOuterSetup_ = function() { // Get shortcut to iframe-element that contains the inner // page. - var innerFrame = this.channel_.iframeElement_; + var innerFrame = this.channel_.getIframeElement(); try { // Attempt to place the NIX wrapper object into the inner // frame's opener property. - innerFrame.contentWindow.opener = - this.getWindow()[goog.net.xpc.NixTransport.NIX_GET_WRAPPER] - (this, this.authToken_); + var theWindow = this.getWindow(); + var getWrapper = theWindow[goog.net.xpc.NixTransport.NIX_GET_WRAPPER]; + innerFrame.contentWindow.opener = getWrapper(this, this.authToken_); this.localSetupCompleted_ = true; } catch (e) { @@ -376,14 +380,14 @@ goog.net.xpc.NixTransport.prototype.attemptInnerSetup_ = function() { // Complete the construction of the channel by sending our own // wrapper to the container via the channel they gave us. - this.nixChannel_['CreateChannel']( - this.getWindow()[goog.net.xpc.NixTransport.NIX_GET_WRAPPER](this, - this.authToken_)); + var theWindow = this.getWindow(); + var getWrapper = theWindow[goog.net.xpc.NixTransport.NIX_GET_WRAPPER]; + this.nixChannel_['CreateChannel'](getWrapper(this, this.authToken_)); this.localSetupCompleted_ = true; // Notify channel that the transport is ready. - this.channel_.notifyConnected_(); + this.channel_.notifyConnected(); } } catch (e) { @@ -408,25 +412,25 @@ goog.net.xpc.NixTransport.prototype.attemptInnerSetup_ = function() { * @private */ goog.net.xpc.NixTransport.prototype.createChannel_ = function(channel) { - // Verify that the channel is in fact a NIX wrapper. - if (typeof channel != 'unknown' || - !(goog.net.xpc.NixTransport.NIX_ID_FIELD in channel)) { - goog.net.xpc.logger.severe('Invalid NIX channel given to createChannel_'); - } + // Verify that the channel is in fact a NIX wrapper. + if (typeof channel != 'unknown' || + !(goog.net.xpc.NixTransport.NIX_ID_FIELD in channel)) { + goog.net.xpc.logger.severe('Invalid NIX channel given to createChannel_'); + } - this.nixChannel_ = channel; + this.nixChannel_ = channel; - // Ensure that the NIX channel given to use is valid. - var remoteAuthToken = this.nixChannel_['GetAuthToken'](); + // Ensure that the NIX channel given to use is valid. + var remoteAuthToken = this.nixChannel_['GetAuthToken'](); - if (remoteAuthToken != this.remoteAuthToken_) { - goog.net.xpc.logger.severe('Invalid auth token from other party'); - return; - } + if (remoteAuthToken != this.remoteAuthToken_) { + goog.net.xpc.logger.severe('Invalid auth token from other party'); + return; + } - // Indicate to the CrossPageChannel that the channel is setup - // and ready to use. - this.channel_.notifyConnected_(); + // Indicate to the CrossPageChannel that the channel is setup + // and ready to use. + this.channel_.notifyConnected(); }; @@ -440,11 +444,10 @@ goog.net.xpc.NixTransport.prototype.createChannel_ = function(channel) { */ goog.net.xpc.NixTransport.prototype.handleMessage_ = function(serviceName, payload) { - - function deliveryHandler() { - this.channel_.deliver_(serviceName, payload); - } - + /** @this {goog.net.xpc.NixTransport} */ + var deliveryHandler = function() { + this.channel_.xpcDeliver(serviceName, payload); + }; this.getWindow().setTimeout(goog.bind(deliveryHandler, this), 1); }; @@ -454,6 +457,7 @@ goog.net.xpc.NixTransport.prototype.handleMessage_ = * @param {string} service The name of the service the message is to be * delivered to. * @param {string} payload The message content. + * @override */ goog.net.xpc.NixTransport.prototype.send = function(service, payload) { // Verify that the NIX channel we have is valid. diff --git a/contexts/data/lib/closure-library/closure/goog/net/xpc/testdata/.svn/all-wcprops b/contexts/data/lib/closure-library/closure/goog/net/xpc/testdata/.svn/all-wcprops deleted file mode 100644 index 70d4082..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/xpc/testdata/.svn/all-wcprops +++ /dev/null @@ -1,11 +0,0 @@ -K 25 -svn:wc:ra_dav:version-url -V 53 -/svn/!svn/ver/850/trunk/closure/goog/net/xpc/testdata -END -inner_peer.html -K 25 -svn:wc:ra_dav:version-url -V 69 -/svn/!svn/ver/850/trunk/closure/goog/net/xpc/testdata/inner_peer.html -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/xpc/testdata/.svn/entries b/contexts/data/lib/closure-library/closure/goog/net/xpc/testdata/.svn/entries deleted file mode 100644 index 1546951..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/xpc/testdata/.svn/entries +++ /dev/null @@ -1,62 +0,0 @@ -10 - -dir -1494 -http://closure-library.googlecode.com/svn/trunk/closure/goog/net/xpc/testdata -http://closure-library.googlecode.com/svn - - - -2011-04-12T20:35:47.000000Z -850 -diegosalas@google.com - - - - - - - - - - - - - - -0b95b8e8-c90f-11de-9d4f-f947ee5921c8 - -inner_peer.html -file - - - - -2011-12-23T22:42:30.122351Z -8ebad8dd356b11b51e61f3a141b470f1 -2011-04-12T20:35:47.000000Z -850 -diegosalas@google.com -has-props - - - - - - - - - - - - - - - - - - - - -2646 - diff --git a/contexts/data/lib/closure-library/closure/goog/net/xpc/testdata/.svn/prop-base/inner_peer.html.svn-base b/contexts/data/lib/closure-library/closure/goog/net/xpc/testdata/.svn/prop-base/inner_peer.html.svn-base deleted file mode 100644 index d356868..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/xpc/testdata/.svn/prop-base/inner_peer.html.svn-base +++ /dev/null @@ -1,5 +0,0 @@ -K 13 -svn:mime-type -V 9 -text/html -END diff --git a/contexts/data/lib/closure-library/closure/goog/net/xpc/testdata/.svn/text-base/inner_peer.html.svn-base b/contexts/data/lib/closure-library/closure/goog/net/xpc/testdata/.svn/text-base/inner_peer.html.svn-base deleted file mode 100644 index 3d9530b..0000000 --- a/contexts/data/lib/closure-library/closure/goog/net/xpc/testdata/.svn/text-base/inner_peer.html.svn-base +++ /dev/null @@ -1,106 +0,0 @@ -<!DOCTYPE html> -<!-- - - This file is responsible for setting up the inner peer half of an XPC - communication channel. It instantiates a CrossPageChannel and attempts to - connect to the outer peer. The XPC configuration should match that of the - outer peer (i.e. same channel name, polling URIs, etc). ---> -<html> -<!-- -Copyright 2009 The Closure Library Authors. All Rights Reserved. - -Use of this source code is governed by the Apache License, Version 2.0. -See the COPYING file for details. ---> - -<head> -<script src="../../../base.js"></script> -<script> -goog.require('goog.debug.Logger'); -goog.require('goog.dom'); -goog.require('goog.events'); -goog.require('goog.events.EventType'); -goog.require('goog.net.xpc.CrossPageChannel'); -</script> -<script> -var channel; -var queuedMessage; - -function clearDebug() { - document.getElementById('debugDiv').innerHTML = ''; -} - -function instantiateChannel(cfg) { - if (window.channel) { - window.channel.dispose(); - } - window.channel = new goog.net.xpc.CrossPageChannel(cfg); - window.channel.registerService('echo', echoHandler); -} - -function connectChannel(opt_callback) { - var callback = opt_callback || goog.nullFunction; - - window.channel.connect(function() { - callback(); - - var message = window.queuedMessage; - if (message) { - window.queuedMessage = null; - echoHandler(message); - } - }); -} - -function isConnected() { - return window.channel && window.channel.isConnected(); -} - -function echoHandler(payload) { - // TODO(user): Works around the bug where the parent - // can get the connect callback before the child is - // marked as connected. - if (isConnected()) { - window.channel.send('msg', payload); - } else { - window.queuedMessage = payload; - } -} - -function handleLoad(evt) { - // Get the channel configuration passed by the containing document. - var xpc = (new goog.Uri(window.location.href)).getParameterValue('xpc'); - if (xpc) { - var cfg = goog.json.parse(xpc); - instantiateChannel(cfg); - connectChannel(); - } -} - -goog.events.listen(window, goog.events.EventType.LOAD, handleLoad); - -</script> -</head> - -<body> - -<div style="position:absolute"> - Debug [<a href="#" onclick="clearDebug()">clear</a>]: <br> - <div id=debugDiv style="border: 1px #000000 solid; font-size:xx-small"></div> -</div> - -<script> -var debugDiv = goog.dom.getElement('debugDiv'); -var logger = goog.debug.Logger.getLogger('goog.net.xpc'); -logger.setLevel(goog.debug.Logger.Level.ALL); -logger.addHandler(function(logRecord) { - var msgElm = goog.dom.createDom('div'); - msgElm.innerHTML = logRecord.getMessage(); - goog.dom.appendChild(debugDiv, msgElm); -}); -</script> - -</body> - -</html> diff --git a/contexts/data/lib/closure-library/closure/goog/net/xpc/testdata/access_checker.html b/contexts/data/lib/closure-library/closure/goog/net/xpc/testdata/access_checker.html new file mode 100644 index 0000000..10a421e --- /dev/null +++ b/contexts/data/lib/closure-library/closure/goog/net/xpc/testdata/access_checker.html @@ -0,0 +1,29 @@ +<!DOCTYPE html> +<!-- + + This file checks whether the current browser can access properties from same + domain iframes. This is currently a problem on the matrix brower ie6 and xp. + For some reason it can't access same domain iframes. + TODO(user): Figure out why it can't. + --> +<html> + <!-- + Copyright 2011 The Closure Library Authors. All Rights Reserved. + + Use of this source code is governed by the Apache License, Version 2.0. + See the COPYING file for details. + --> + <head> + <title>The access checking iframe</title> + </head> + <body> + <script type="text/javascript"> + try { + var sameDomainIframeHref = parent.frames['nonexistant'].location.href; + parent.sameDomainIframeAccessComplete(true); + } catch (e) { + parent.sameDomainIframeAccessComplete(false); + } + </script> + </body> +</html> diff --git a/contexts/data/lib/closure-library/closure/goog/net/xpc/testdata/inner_peer.html b/contexts/data/lib/closure-library/closure/goog/net/xpc/testdata/inner_peer.html index 3d9530b..5542f79 100644 --- a/contexts/data/lib/closure-library/closure/goog/net/xpc/testdata/inner_peer.html +++ b/contexts/data/lib/closure-library/closure/goog/net/xpc/testdata/inner_peer.html @@ -15,18 +15,21 @@ See the COPYING file for details. --> <head> -<script src="../../../base.js"></script> -<script> +<title>XPC test inner frame</title> +<script src="../../../base.js" type="text/javascript"></script> +<script type="text/javascript"> goog.require('goog.debug.Logger'); goog.require('goog.dom'); goog.require('goog.events'); goog.require('goog.events.EventType'); goog.require('goog.net.xpc.CrossPageChannel'); </script> -<script> +<script type="text/javascript"> var channel; var queuedMessage; +var OBJECT_RESULT_FROM_SERVICE = {'favorites': 'pie'}; + function clearDebug() { document.getElementById('debugDiv').innerHTML = ''; } @@ -37,49 +40,35 @@ function instantiateChannel(cfg) { } window.channel = new goog.net.xpc.CrossPageChannel(cfg); window.channel.registerService('echo', echoHandler); + window.channel.registerService('response', responseHandler); + connectChannel( + parent.driver && parent.driver.innerFrameConnected ? + goog.bind(parent.driver.innerFrameConnected, parent.driver) : null); } function connectChannel(opt_callback) { - var callback = opt_callback || goog.nullFunction; + window.channel.connect(opt_callback || goog.nullFunction); +} - window.channel.connect(function() { - callback(); +function sendEcho(payload) { + window.channel.send('echo', payload); +} - var message = window.queuedMessage; - if (message) { - window.queuedMessage = null; - echoHandler(message); - } - }); +function echoHandler(payload) { + window.channel.send('response', payload); + return OBJECT_RESULT_FROM_SERVICE; } function isConnected() { return window.channel && window.channel.isConnected(); } -function echoHandler(payload) { - // TODO(user): Works around the bug where the parent - // can get the connect callback before the child is - // marked as connected. - if (isConnected()) { - window.channel.send('msg', payload); - } else { - window.queuedMessage = payload; - } -} - -function handleLoad(evt) { - // Get the channel configuration passed by the containing document. - var xpc = (new goog.Uri(window.location.href)).getParameterValue('xpc'); - if (xpc) { - var cfg = goog.json.parse(xpc); - instantiateChannel(cfg); - connectChannel(); +function responseHandler(payload) { + if (parent.driver && parent.driver.innerFrameGotResponse) { + parent.driver.innerFrameGotResponse(payload); } } -goog.events.listen(window, goog.events.EventType.LOAD, handleLoad); - </script> </head> @@ -90,7 +79,7 @@ goog.events.listen(window, goog.events.EventType.LOAD, handleLoad); <div id=debugDiv style="border: 1px #000000 solid; font-size:xx-small"></div> </div> -<script> +<script type="text/javascript"> var debugDiv = goog.dom.getElement('debugDiv'); var logger = goog.debug.Logger.getLogger('goog.net.xpc'); logger.setLevel(goog.debug.Logger.Level.ALL); @@ -99,6 +88,7 @@ logger.addHandler(function(logRecord) { msgElm.innerHTML = logRecord.getMessage(); goog.dom.appendChild(debugDiv, msgElm); }); + </script> </body> diff --git a/contexts/data/lib/closure-library/closure/goog/net/xpc/transport.js b/contexts/data/lib/closure-library/closure/goog/net/xpc/transport.js index b9148af..6f63651 100644 --- a/contexts/data/lib/closure-library/closure/goog/net/xpc/transport.js +++ b/contexts/data/lib/closure-library/closure/goog/net/xpc/transport.js @@ -90,7 +90,7 @@ goog.net.xpc.Transport.prototype.transportServiceHandler = goog.abstractMethod; /** * Connects this transport. * The transport implementation is expected to call - * CrossPageChannel.prototype.notifyConnected_ when the channel is ready + * CrossPageChannel.prototype.notifyConnected when the channel is ready * to be used. */ goog.net.xpc.Transport.prototype.connect = goog.abstractMethod; @@ -100,6 +100,6 @@ goog.net.xpc.Transport.prototype.connect = goog.abstractMethod; * Sends a message. * @param {string} service The name off the service the message is to be * delivered to. - * @param {string|Object} payload The message content. + * @param {string} payload The message content. */ goog.net.xpc.Transport.prototype.send = goog.abstractMethod; diff --git a/contexts/data/lib/closure-library/closure/goog/net/xpc/xpc.js b/contexts/data/lib/closure-library/closure/goog/net/xpc/xpc.js index c74a349..be1b62e 100644 --- a/contexts/data/lib/closure-library/closure/goog/net/xpc/xpc.js +++ b/contexts/data/lib/closure-library/closure/goog/net/xpc/xpc.js @@ -148,7 +148,45 @@ goog.net.xpc.CfgFields = { * (if specified). Used for security sensitive applications that make * use of NativeMessagingTransport (i.e. most applications). */ - PEER_HOSTNAME: 'ph' + PEER_HOSTNAME: 'ph', + /** + * Usually both frames using a connection initially send a SETUP message to + * each other, and each responds with a SETUP_ACK. A frame marks itself + * connected when it receives that SETUP_ACK. If this parameter is true + * however, the channel it is passed to will not send a SETUP, but rather will + * wait for one from its peer and mark itself connected when that arrives. + * Peer iframes created using such a channel will send SETUP however, and will + * wait for SETUP_ACK before marking themselves connected. The goal is to + * cope with a situation where the availability of the URL for the peer frame + * cannot be relied on, eg when the application is offline. Without this + * setting, the primary frame will attempt to send its SETUP message every + * 100ms, forever. This floods the javascript console with uncatchable + * security warnings, and fruitlessly burns CPU. There is one scenario this + * mode will not support, and that is reconnection by the outer frame, ie the + * creation of a new channel object to connect to a peer iframe which was + * already communicating with a previous channel object of the same name. If + * that behavior is needed, this mode should not be used. Reconnection by + * inner frames is supported in this mode however. + */ + ONE_SIDED_HANDSHAKE: 'osh', + /** + * The frame role (inner or outer). Used to explicitly indicate the role for + * each peer whenever the role cannot be reliably determined (e.g. the two + * peer windows are not parent/child frames). If unspecified, the role will + * be dynamically determined, assuming a parent/child frame setup. + */ + ROLE: 'role', + /** + * Which version of the native transport startup protocol should be used, the + * default being '2'. Version 1 had various timing vulnerabilities, which + * had to be compensated for by introducing delays, and is deprecated. V1 + * and V2 are broadly compatible, although the more robust timing and lack + * of delays is not gained unless both sides are using V2. The only + * unsupported case of cross-protocol interoperation is where a connection + * starts out with V2 at both ends, and one of the ends reconnects as a V1. + * All other initial startup and reconnection scenarios are supported. + */ + NATIVE_TRANSPORT_PROTOCOL_VERSION: 'nativeProtocolVersion' }; @@ -178,31 +216,47 @@ goog.net.xpc.ChannelStates = { /** * The name of the transport service (used for internal signalling). * @type {string} - * @private + * @suppress {underscore} */ goog.net.xpc.TRANSPORT_SERVICE_ = 'tp'; /** * Transport signaling message: setup. - * @protected + * @type {string} */ goog.net.xpc.SETUP = 'SETUP'; /** + * Transport signaling message: setup for native transport protocol v2. + * @type {string} + */ +goog.net.xpc.SETUP_NTPV2 = 'SETUP_NTPV2'; + + +/** * Transport signaling message: setup acknowledgement. - * @private + * @type {string} + * @suppress {underscore} */ goog.net.xpc.SETUP_ACK_ = 'SETUP_ACK'; /** + * Transport signaling message: setup acknowledgement. + * @type {string} + */ +goog.net.xpc.SETUP_ACK_NTPV2 = 'SETUP_ACK_NTPV2'; + + +/** * Object holding active channels. - * @type {Object} - * @private + * Package private. Do not call from outside goog.net.xpc. + * + * @type {Object.<string, goog.net.xpc.CrossPageChannel>} */ -goog.net.xpc.channels_ = {}; +goog.net.xpc.channels = {}; /** |