webchannelbasetransport.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471
  1. // Copyright 2013 The Closure Library Authors. All Rights Reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS-IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. /**
  15. * @fileoverview Implementation of a WebChannel transport using WebChannelBase.
  16. *
  17. * When WebChannelBase is used as the underlying transport, the capabilities
  18. * of the WebChannel are limited to what's supported by the implementation.
  19. * Particularly, multiplexing is not possible, and only strings are
  20. * supported as message types.
  21. *
  22. */
  23. goog.provide('goog.labs.net.webChannel.WebChannelBaseTransport');
  24. goog.require('goog.asserts');
  25. goog.require('goog.events.EventTarget');
  26. goog.require('goog.json');
  27. goog.require('goog.labs.net.webChannel.ChannelRequest');
  28. goog.require('goog.labs.net.webChannel.WebChannelBase');
  29. goog.require('goog.log');
  30. goog.require('goog.net.WebChannel');
  31. goog.require('goog.net.WebChannelTransport');
  32. goog.require('goog.object');
  33. goog.require('goog.string');
  34. goog.require('goog.string.path');
  35. /**
  36. * Implementation of {@link goog.net.WebChannelTransport} with
  37. * {@link goog.labs.net.webChannel.WebChannelBase} as the underlying channel
  38. * implementation.
  39. *
  40. * @constructor
  41. * @struct
  42. * @implements {goog.net.WebChannelTransport}
  43. * @final
  44. */
  45. goog.labs.net.webChannel.WebChannelBaseTransport = function() {
  46. if (!goog.labs.net.webChannel.ChannelRequest.supportsXhrStreaming()) {
  47. throw new Error('Environmental error: no available transport.');
  48. }
  49. };
  50. goog.scope(function() {
  51. var WebChannelBaseTransport = goog.labs.net.webChannel.WebChannelBaseTransport;
  52. var WebChannelBase = goog.labs.net.webChannel.WebChannelBase;
  53. /**
  54. * @override
  55. */
  56. WebChannelBaseTransport.prototype.createWebChannel = function(
  57. url, opt_options) {
  58. return new WebChannelBaseTransport.Channel(url, opt_options);
  59. };
  60. /**
  61. * Implementation of the {@link goog.net.WebChannel} interface.
  62. *
  63. * @param {string} url The URL path for the new WebChannel instance.
  64. * @param {!goog.net.WebChannel.Options=} opt_options Configuration for the
  65. * new WebChannel instance.
  66. *
  67. * @constructor
  68. * @implements {goog.net.WebChannel}
  69. * @extends {goog.events.EventTarget}
  70. * @final
  71. */
  72. WebChannelBaseTransport.Channel = function(url, opt_options) {
  73. WebChannelBaseTransport.Channel.base(this, 'constructor');
  74. /**
  75. * @private {!WebChannelBase} The underlying channel object.
  76. */
  77. this.channel_ = new WebChannelBase(
  78. opt_options, goog.net.WebChannelTransport.CLIENT_VERSION);
  79. /**
  80. * @private {string} The URL of the target server end-point.
  81. */
  82. this.url_ = url;
  83. /**
  84. * The test URL of the target server end-point. This value defaults to
  85. * this.url_ + '/test'.
  86. *
  87. * @private {string}
  88. */
  89. this.testUrl_ = (opt_options && opt_options.testUrl) ?
  90. opt_options.testUrl :
  91. goog.string.path.join(this.url_, 'test');
  92. /**
  93. * @private {goog.log.Logger} The logger for this class.
  94. */
  95. this.logger_ =
  96. goog.log.getLogger('goog.labs.net.webChannel.WebChannelBaseTransport');
  97. /**
  98. * @private {Object<string, string>} Extra URL parameters
  99. * to be added to each HTTP request.
  100. */
  101. this.messageUrlParams_ =
  102. (opt_options && opt_options.messageUrlParams) || null;
  103. var messageHeaders = (opt_options && opt_options.messageHeaders) || null;
  104. // default is false
  105. if (opt_options && opt_options.clientProtocolHeaderRequired) {
  106. if (messageHeaders) {
  107. goog.object.set(
  108. messageHeaders, goog.net.WebChannel.X_CLIENT_PROTOCOL,
  109. goog.net.WebChannel.X_CLIENT_PROTOCOL_WEB_CHANNEL);
  110. } else {
  111. messageHeaders = goog.object.create(
  112. goog.net.WebChannel.X_CLIENT_PROTOCOL,
  113. goog.net.WebChannel.X_CLIENT_PROTOCOL_WEB_CHANNEL);
  114. }
  115. }
  116. this.channel_.setExtraHeaders(messageHeaders);
  117. var initHeaders = (opt_options && opt_options.initMessageHeaders) || null;
  118. this.channel_.setInitHeaders(initHeaders);
  119. var httpHeadersOverwriteParam =
  120. opt_options && opt_options.httpHeadersOverwriteParam;
  121. if (httpHeadersOverwriteParam &&
  122. !goog.string.isEmptyOrWhitespace(httpHeadersOverwriteParam)) {
  123. this.channel_.setHttpHeadersOverwriteParam(httpHeadersOverwriteParam);
  124. }
  125. /**
  126. * @private {boolean} Whether to enable CORS.
  127. */
  128. this.supportsCrossDomainXhr_ =
  129. (opt_options && opt_options.supportsCrossDomainXhr) || false;
  130. /**
  131. * @private {boolean} Whether to send raw Json and bypass v8 wire format.
  132. */
  133. this.sendRawJson_ = (opt_options && opt_options.sendRawJson) || false;
  134. // Note that httpSessionIdParam will be ignored if the same parameter name
  135. // has already been specified with messageUrlParams
  136. var httpSessionIdParam = opt_options && opt_options.httpSessionIdParam;
  137. if (httpSessionIdParam &&
  138. !goog.string.isEmptyOrWhitespace(httpSessionIdParam)) {
  139. this.channel_.setHttpSessionIdParam(httpSessionIdParam);
  140. if (goog.object.containsKey(this.messageUrlParams_, httpSessionIdParam)) {
  141. goog.object.remove(this.messageUrlParams_, httpSessionIdParam);
  142. goog.log.warning(this.logger_,
  143. 'Ignore httpSessionIdParam also specified with messageUrlParams: '
  144. + httpSessionIdParam);
  145. }
  146. }
  147. /**
  148. * The channel handler.
  149. *
  150. * @private {!WebChannelBaseTransport.Channel.Handler_}
  151. */
  152. this.channelHandler_ = new WebChannelBaseTransport.Channel.Handler_(this);
  153. };
  154. goog.inherits(WebChannelBaseTransport.Channel, goog.events.EventTarget);
  155. /**
  156. * @override
  157. * @suppress {checkTypes}
  158. */
  159. WebChannelBaseTransport.Channel.prototype.addEventListener = function(
  160. type, handler, /** boolean= */ opt_capture, opt_handlerScope) {
  161. WebChannelBaseTransport.Channel.base(
  162. this, 'addEventListener', type, handler, opt_capture, opt_handlerScope);
  163. };
  164. /**
  165. * @override
  166. * @suppress {checkTypes}
  167. */
  168. WebChannelBaseTransport.Channel.prototype.removeEventListener = function(
  169. type, handler, /** boolean= */ opt_capture, opt_handlerScope) {
  170. WebChannelBaseTransport.Channel.base(
  171. this, 'removeEventListener', type, handler, opt_capture,
  172. opt_handlerScope);
  173. };
  174. /**
  175. * Test path is always set to "/url/test".
  176. *
  177. * @override
  178. */
  179. WebChannelBaseTransport.Channel.prototype.open = function() {
  180. this.channel_.setHandler(this.channelHandler_);
  181. if (this.supportsCrossDomainXhr_) {
  182. this.channel_.setSupportsCrossDomainXhrs(true);
  183. }
  184. this.channel_.connect(
  185. this.testUrl_, this.url_, (this.messageUrlParams_ || undefined));
  186. };
  187. /**
  188. * @override
  189. */
  190. WebChannelBaseTransport.Channel.prototype.close = function() {
  191. this.channel_.disconnect();
  192. };
  193. /**
  194. * The WebChannelBase only supports object types.
  195. *
  196. * @param {!goog.net.WebChannel.MessageData} message The message to send.
  197. *
  198. * @override
  199. */
  200. WebChannelBaseTransport.Channel.prototype.send = function(message) {
  201. goog.asserts.assert(goog.isObject(message), 'only object type expected');
  202. if (this.sendRawJson_) {
  203. var rawJson = {};
  204. rawJson['__data__'] = goog.json.serialize(message);
  205. this.channel_.sendMap(rawJson);
  206. } else {
  207. this.channel_.sendMap(message);
  208. }
  209. };
  210. /**
  211. * @override
  212. */
  213. WebChannelBaseTransport.Channel.prototype.disposeInternal = function() {
  214. this.channel_.setHandler(null);
  215. delete this.channelHandler_;
  216. this.channel_.disconnect();
  217. delete this.channel_;
  218. WebChannelBaseTransport.Channel.base(this, 'disposeInternal');
  219. };
  220. /**
  221. * The message event.
  222. *
  223. * @param {!Array<?>} array The data array from the underlying channel.
  224. * @constructor
  225. * @extends {goog.net.WebChannel.MessageEvent}
  226. * @final
  227. */
  228. WebChannelBaseTransport.Channel.MessageEvent = function(array) {
  229. WebChannelBaseTransport.Channel.MessageEvent.base(this, 'constructor');
  230. this.data = array;
  231. };
  232. goog.inherits(
  233. WebChannelBaseTransport.Channel.MessageEvent,
  234. goog.net.WebChannel.MessageEvent);
  235. /**
  236. * The error event.
  237. *
  238. * @param {WebChannelBase.Error} error The error code.
  239. * @constructor
  240. * @extends {goog.net.WebChannel.ErrorEvent}
  241. * @final
  242. */
  243. WebChannelBaseTransport.Channel.ErrorEvent = function(error) {
  244. WebChannelBaseTransport.Channel.ErrorEvent.base(this, 'constructor');
  245. /**
  246. * High-level status code.
  247. */
  248. this.status = goog.net.WebChannel.ErrorStatus.NETWORK_ERROR;
  249. /**
  250. * @const {WebChannelBase.Error} Internal error code, for debugging use only.
  251. */
  252. this.errorCode = error;
  253. };
  254. goog.inherits(
  255. WebChannelBaseTransport.Channel.ErrorEvent, goog.net.WebChannel.ErrorEvent);
  256. /**
  257. * Implementation of {@link WebChannelBase.Handler} interface.
  258. *
  259. * @param {!WebChannelBaseTransport.Channel} channel The enclosing WebChannel.
  260. *
  261. * @constructor
  262. * @extends {WebChannelBase.Handler}
  263. * @private
  264. */
  265. WebChannelBaseTransport.Channel.Handler_ = function(channel) {
  266. WebChannelBaseTransport.Channel.Handler_.base(this, 'constructor');
  267. /**
  268. * @type {!WebChannelBaseTransport.Channel}
  269. * @private
  270. */
  271. this.channel_ = channel;
  272. };
  273. goog.inherits(WebChannelBaseTransport.Channel.Handler_, WebChannelBase.Handler);
  274. /**
  275. * @override
  276. */
  277. WebChannelBaseTransport.Channel.Handler_.prototype.channelOpened = function(
  278. channel) {
  279. goog.log.info(
  280. this.channel_.logger_, 'WebChannel opened on ' + this.channel_.url_);
  281. this.channel_.dispatchEvent(goog.net.WebChannel.EventType.OPEN);
  282. };
  283. /**
  284. * @override
  285. */
  286. WebChannelBaseTransport.Channel.Handler_.prototype.channelHandleArray =
  287. function(channel, array) {
  288. goog.asserts.assert(array, 'array expected to be defined');
  289. this.channel_.dispatchEvent(
  290. new WebChannelBaseTransport.Channel.MessageEvent(array));
  291. };
  292. /**
  293. * @override
  294. */
  295. WebChannelBaseTransport.Channel.Handler_.prototype.channelError = function(
  296. channel, error) {
  297. goog.log.info(
  298. this.channel_.logger_, 'WebChannel aborted on ' + this.channel_.url_ +
  299. ' due to channel error: ' + error);
  300. this.channel_.dispatchEvent(
  301. new WebChannelBaseTransport.Channel.ErrorEvent(error));
  302. };
  303. /**
  304. * @override
  305. */
  306. WebChannelBaseTransport.Channel.Handler_.prototype.channelClosed = function(
  307. channel, opt_pendingMaps, opt_undeliveredMaps) {
  308. goog.log.info(
  309. this.channel_.logger_, 'WebChannel closed on ' + this.channel_.url_);
  310. this.channel_.dispatchEvent(goog.net.WebChannel.EventType.CLOSE);
  311. };
  312. /**
  313. * @override
  314. */
  315. WebChannelBaseTransport.Channel.prototype.getRuntimeProperties = function() {
  316. return new WebChannelBaseTransport.ChannelProperties(this.channel_);
  317. };
  318. /**
  319. * Implementation of the {@link goog.net.WebChannel.RuntimeProperties}.
  320. *
  321. * @param {!WebChannelBase} channel The underlying channel object.
  322. *
  323. * @constructor
  324. * @implements {goog.net.WebChannel.RuntimeProperties}
  325. * @final
  326. */
  327. WebChannelBaseTransport.ChannelProperties = function(channel) {
  328. /**
  329. * The underlying channel object.
  330. *
  331. * @private {!WebChannelBase}
  332. */
  333. this.channel_ = channel;
  334. };
  335. /**
  336. * @override
  337. */
  338. WebChannelBaseTransport.ChannelProperties.prototype.getConcurrentRequestLimit =
  339. function() {
  340. return this.channel_.getForwardChannelRequestPool().getMaxSize();
  341. };
  342. /**
  343. * @override
  344. */
  345. WebChannelBaseTransport.ChannelProperties.prototype.isSpdyEnabled = function() {
  346. return this.getConcurrentRequestLimit() > 1;
  347. };
  348. /**
  349. * @override
  350. */
  351. WebChannelBaseTransport.ChannelProperties.prototype.getHttpSessionId =
  352. function() {
  353. return this.channel_.getHttpSessionId();
  354. };
  355. /**
  356. * @override
  357. */
  358. WebChannelBaseTransport.ChannelProperties.prototype.commit =
  359. goog.abstractMethod;
  360. /**
  361. * @override
  362. */
  363. WebChannelBaseTransport.ChannelProperties.prototype.getNonAckedMessageCount =
  364. goog.abstractMethod;
  365. /**
  366. * @override
  367. */
  368. WebChannelBaseTransport.ChannelProperties.prototype.notifyNonAckedMessageCount =
  369. goog.abstractMethod;
  370. /**
  371. * @override
  372. */
  373. WebChannelBaseTransport.ChannelProperties.prototype.onCommit =
  374. goog.abstractMethod;
  375. /**
  376. * @override
  377. */
  378. WebChannelBaseTransport.ChannelProperties.prototype.ackCommit =
  379. goog.abstractMethod;
  380. /** @override */
  381. WebChannelBaseTransport.ChannelProperties.prototype.getLastStatusCode =
  382. function() {
  383. return this.channel_.getLastStatusCode();
  384. };
  385. }); // goog.scope