webchannel.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475
  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 The API spec for the WebChannel messaging library.
  16. *
  17. * Similar to HTML5 WebSocket and Closure BrowserChannel, WebChannel
  18. * offers an abstraction for point-to-point socket-like communication between
  19. * a browser client and a remote origin.
  20. *
  21. * WebChannels are created via <code>WebChannel</code>. Multiple WebChannels
  22. * may be multiplexed over the same WebChannelTransport, which represents
  23. * the underlying physical connectivity over standard wire protocols
  24. * such as HTTP and SPDY.
  25. *
  26. * A WebChannels in turn represents a logical communication channel between
  27. * the client and server end point. A WebChannel remains open for
  28. * as long as the client or server end-point allows.
  29. *
  30. * Messages may be delivered in-order or out-of-order, reliably or unreliably
  31. * over the same WebChannel. Message delivery guarantees of a WebChannel is
  32. * to be specified by the application code; and the choice of the
  33. * underlying wire protocols is completely transparent to the API users.
  34. *
  35. * Client-to-client messaging via WebRTC based transport may also be support
  36. * via the same WebChannel API in future.
  37. *
  38. * Note that we have no immediate plan to move this API out of labs. While
  39. * the implementation is production ready, the API is subject to change
  40. * (addition only):
  41. * 1. Adopt new Web APIs (mainly whatwg streams) and goog.net.streams.
  42. * 2. New programming models for cloud (on the server-side) may require
  43. * new APIs to be defined.
  44. * 3. WebRTC DataChannel alignment
  45. *
  46. */
  47. goog.provide('goog.net.WebChannel');
  48. goog.require('goog.events');
  49. goog.require('goog.events.Event');
  50. /**
  51. * A WebChannel represents a logical bi-directional channel over which the
  52. * client communicates with a remote server that holds the other endpoint
  53. * of the channel. A WebChannel is always created in the context of a shared
  54. * {@link WebChannelTransport} instance. It is up to the underlying client-side
  55. * and server-side implementations to decide how or when multiplexing is
  56. * to be enabled.
  57. *
  58. * @interface
  59. * @extends {EventTarget}
  60. */
  61. goog.net.WebChannel = function() {};
  62. /**
  63. * Configuration spec for newly created WebChannel instances.
  64. *
  65. * WebChannels are configured in the context of the containing
  66. * {@link WebChannelTransport}. The configuration parameters are specified
  67. * when a new instance of WebChannel is created via {@link WebChannelTransport}.
  68. *
  69. * messageHeaders: custom headers to be added to every message sent to the
  70. * server. This object is mutable, and custom headers may be changed, removed,
  71. * or added during the runtime after a channel has been opened.
  72. *
  73. * initMessageHeaders: similar to messageHeaders, but any custom headers will
  74. * be sent only once when the channel is opened. Typical usage is to send
  75. * an auth header to the server, which only checks the auth header at the time
  76. * when the channel is opened.
  77. *
  78. * messageUrlParams: custom url query parameters to be added to every message
  79. * sent to the server. This object is mutable, and custom parameters may be
  80. * changed, removed or added during the runtime after a channel has been opened.
  81. *
  82. * clientProtocolHeaderRequired: whether a special header should be added to
  83. * each message so that the server can dispatch webchannel messages without
  84. * knowing the URL path prefix. Defaults to false.
  85. *
  86. * concurrentRequestLimit: the maximum number of in-flight HTTP requests allowed
  87. * when SPDY is enabled. Currently we only detect SPDY in Chrome.
  88. * This parameter defaults to 10. When SPDY is not enabled, this parameter
  89. * will have no effect.
  90. *
  91. * supportsCrossDomainXhr: setting this to true to allow the use of sub-domains
  92. * (as configured by the server) to send XHRs with the CORS withCredentials
  93. * bit set to true.
  94. *
  95. * testUrl: the test URL for detecting connectivity during the initial
  96. * handshake. This parameter defaults to "/<channel_url>/test".
  97. *
  98. * sendRawJson: whether to bypass v8 encoding of client-sent messages. Will be
  99. * deprecated after v9 wire protocol is introduced. Only safe to set if the
  100. * server is known to support this feature.
  101. *
  102. * httpSessionIdParam: the URL parameter name that contains the session id (
  103. * for sticky routing of HTTP requests). When this param is specified, a server
  104. * that supports this option will respond with an opaque session id as part of
  105. * the initial handshake (via the X-HTTP-Session-Id header); and all the
  106. * subsequent requests will contain the httpSessionIdParam. This option will
  107. * take precedence over any duplicated parameter specified with
  108. * messageUrlParams, whose value will be ignored.
  109. *
  110. * httpHeadersOverwriteParam: the URL parameter name to allow custom HTTP
  111. * headers to be overwritten as a URL param to bypass CORS preflight.
  112. * goog.net.rpc.HttpCors is used to encode the HTTP headers.
  113. *
  114. * backgroundChannelTest: whether to run the channel test (detecting networking
  115. * conditions) as a background process so the OPEN event will be fired sooner
  116. * to reduce the initial handshake delay. This option defaults to true.
  117. *
  118. * fastHandshake: experimental feature to speed up the initial handshake, e.g.
  119. * leveraging QUIC 0-RTT, in-band version negotiation. This option defaults
  120. * to false.
  121. *
  122. * @typedef {{
  123. * messageHeaders: (!Object<string, string>|undefined),
  124. * initMessageHeaders: (!Object<string, string>|undefined),
  125. * messageUrlParams: (!Object<string, string>|undefined),
  126. * clientProtocolHeaderRequired: (boolean|undefined),
  127. * concurrentRequestLimit: (number|undefined),
  128. * supportsCrossDomainXhr: (boolean|undefined),
  129. * testUrl: (string|undefined),
  130. * sendRawJson: (boolean|undefined),
  131. * httpSessionIdParam: (string|undefined),
  132. * httpHeadersOverwriteParam: (string|undefined),
  133. * backgroundChannelTest: (boolean|undefined),
  134. * fastHandshake: (boolean|undefined)
  135. * }}
  136. */
  137. goog.net.WebChannel.Options;
  138. /**
  139. * Types that are allowed as message data.
  140. *
  141. * Note that JS objects (sent by the client) can only have string encoded
  142. * values due to the limitation of the current wire protocol.
  143. *
  144. * Unicode strings (sent by the server) may or may not need be escaped, as
  145. * decided by the server.
  146. *
  147. * @typedef {(ArrayBuffer|Blob|Object<string, string>|Array)}
  148. */
  149. goog.net.WebChannel.MessageData;
  150. /**
  151. * Open the WebChannel against the URI specified in the constructor.
  152. */
  153. goog.net.WebChannel.prototype.open = goog.abstractMethod;
  154. /**
  155. * Close the WebChannel.
  156. */
  157. goog.net.WebChannel.prototype.close = goog.abstractMethod;
  158. /**
  159. * Sends a message to the server that maintains the other end point of
  160. * the WebChannel.
  161. *
  162. * @param {!goog.net.WebChannel.MessageData} message The message to send.
  163. */
  164. goog.net.WebChannel.prototype.send = goog.abstractMethod;
  165. /**
  166. * Common events fired by WebChannels.
  167. * @enum {string}
  168. */
  169. goog.net.WebChannel.EventType = {
  170. /** Dispatched when the channel is opened. */
  171. OPEN: goog.events.getUniqueId('open'),
  172. /** Dispatched when the channel is closed. */
  173. CLOSE: goog.events.getUniqueId('close'),
  174. /**
  175. * Dispatched when the channel is aborted due to errors.
  176. *
  177. * For backward compatibility reasons, a CLOSE event will also be
  178. * dispatched, following the ERROR event, which indicates that the channel
  179. * has been completely shutdown .
  180. */
  181. ERROR: goog.events.getUniqueId('error'),
  182. /** Dispatched when the channel has received a new message. */
  183. MESSAGE: goog.events.getUniqueId('message')
  184. };
  185. /**
  186. * The event interface for the MESSAGE event.
  187. *
  188. * @constructor
  189. * @extends {goog.events.Event}
  190. */
  191. goog.net.WebChannel.MessageEvent = function() {
  192. goog.net.WebChannel.MessageEvent.base(
  193. this, 'constructor', goog.net.WebChannel.EventType.MESSAGE);
  194. };
  195. goog.inherits(goog.net.WebChannel.MessageEvent, goog.events.Event);
  196. /**
  197. * The content of the message received from the server.
  198. *
  199. * @type {!goog.net.WebChannel.MessageData}
  200. */
  201. goog.net.WebChannel.MessageEvent.prototype.data;
  202. /**
  203. * WebChannel level error conditions.
  204. *
  205. * Summary of error debugging and reporting in WebChannel:
  206. *
  207. * Network Error
  208. * 1. By default the webchannel library will set the error status to
  209. * NETWORK_ERROR when a channel has to be aborted or closed. NETWORK_ERROR
  210. * may be recovered by the application by retrying and opening a new channel.
  211. * 2. There may be lost messages (not acked by the server) when a channel is
  212. * aborted. Currently we don't have a public API to retrieve messages that
  213. * are waiting to be acked on the client side. File a bug if you think it
  214. * is useful to expose such an API.
  215. * 3. Details of why a channel fails are available via closure debug logs,
  216. * and stats events (see webchannel/requeststats.js). Those are internal
  217. * stats and are subject to change. File a bug if you think it's useful to
  218. * version and expose such stats as part of the WebChannel API.
  219. *
  220. * Server Error
  221. * 1. SERVER_ERROR is intended to indicate a non-recoverable condition, e.g.
  222. * when auth fails.
  223. * 2. We don't currently generate any such errors, because most of the time
  224. * it's the responsibility of upper-layer frameworks or the application
  225. * itself to indicate to the client why a webchannel has been failed
  226. * by the server.
  227. * 3. When a channel is failed by the server explicitly, we still signal
  228. * NETWORK_ERROR to the client. Explicit server failure may happen when the
  229. * server does a fail-over, or becomes overloaded, or conducts a forced
  230. * shutdown etc.
  231. * 4. We use some heuristic to decide if the network (aka cloud) is down
  232. * v.s. the actual server is down.
  233. *
  234. * RuntimeProperties.getLastStatusCode is a useful state that we expose to
  235. * the client to indicate the HTTP response status code of the last HTTP
  236. * request initiated by the WebChannel client library, for debugging
  237. * purposes only.
  238. *
  239. * @enum {number}
  240. */
  241. goog.net.WebChannel.ErrorStatus = {
  242. /** No error has occurred. */
  243. OK: 0,
  244. /** Communication to the server has failed. */
  245. NETWORK_ERROR: 1,
  246. /** The server fails to accept or process the WebChannel. */
  247. SERVER_ERROR: 2
  248. };
  249. /**
  250. * The event interface for the ERROR event.
  251. *
  252. * @constructor
  253. * @extends {goog.events.Event}
  254. */
  255. goog.net.WebChannel.ErrorEvent = function() {
  256. goog.net.WebChannel.ErrorEvent.base(
  257. this, 'constructor', goog.net.WebChannel.EventType.ERROR);
  258. };
  259. goog.inherits(goog.net.WebChannel.ErrorEvent, goog.events.Event);
  260. /**
  261. * The error status.
  262. *
  263. * @type {!goog.net.WebChannel.ErrorStatus}
  264. */
  265. goog.net.WebChannel.ErrorEvent.prototype.status;
  266. /**
  267. * @return {!goog.net.WebChannel.RuntimeProperties} The runtime properties
  268. * of the WebChannel instance.
  269. */
  270. goog.net.WebChannel.prototype.getRuntimeProperties = goog.abstractMethod;
  271. /**
  272. * The runtime properties of the WebChannel instance.
  273. *
  274. * This class is defined for debugging and monitoring purposes, as well as for
  275. * runtime functions that the application may choose to manage by itself.
  276. *
  277. * @interface
  278. */
  279. goog.net.WebChannel.RuntimeProperties = function() {};
  280. /**
  281. * @return {number} The effective limit for the number of concurrent HTTP
  282. * requests that are allowed to be made for sending messages from the client
  283. * to the server. When SPDY is not enabled, this limit will be one.
  284. */
  285. goog.net.WebChannel.RuntimeProperties.prototype.getConcurrentRequestLimit =
  286. goog.abstractMethod;
  287. /**
  288. * For applications that need support multiple channels (e.g. from
  289. * different tabs) to the same origin, use this method to decide if SPDY is
  290. * enabled and therefore it is safe to open multiple channels.
  291. *
  292. * If SPDY is disabled, the application may choose to limit the number of active
  293. * channels to one or use other means such as sub-domains to work around
  294. * the browser connection limit.
  295. *
  296. * @return {boolean} Whether SPDY is enabled for the origin against which
  297. * the channel is created.
  298. */
  299. goog.net.WebChannel.RuntimeProperties.prototype.isSpdyEnabled =
  300. goog.abstractMethod;
  301. /**
  302. * For applications to query the current HTTP session id, sent by the server
  303. * during the initial handshake.
  304. *
  305. * @return {?string} the HTTP session id or null if no HTTP session is in use.
  306. */
  307. goog.net.WebChannel.RuntimeProperties.prototype.getHttpSessionId =
  308. goog.abstractMethod;
  309. /**
  310. * This method generates an in-band commit request to the server, which will
  311. * ack the commit request as soon as all messages sent prior to this commit
  312. * request have been committed by the application.
  313. *
  314. * Committing a message has a stronger semantics than delivering a message
  315. * to the application. Detail spec:
  316. * https://github.com/bidiweb/webchannel/blob/master/commit.md
  317. *
  318. * Timeout or cancellation is not supported and the application may have to
  319. * abort the channel if the commit-ack fails to arrive in time.
  320. *
  321. * @param {function()} callback The callback will be invoked once an
  322. * ack has been received for the current commit or any newly issued commit.
  323. */
  324. goog.net.WebChannel.RuntimeProperties.prototype.commit = goog.abstractMethod;
  325. /**
  326. * This method may be used by the application to recover from a peer failure
  327. * or to enable sender-initiated flow-control.
  328. *
  329. * Detail spec: https://github.com/bidiweb/webchannel/blob/master/commit.md
  330. *
  331. * @return {number} The total number of messages that have not received
  332. * commit-ack from the server; or if no commit has been issued, the number
  333. * of messages that have not been delivered to the server application.
  334. */
  335. goog.net.WebChannel.RuntimeProperties.prototype.getNonAckedMessageCount =
  336. goog.abstractMethod;
  337. /**
  338. * A low water-mark message count to notify the application when the
  339. * flow-control condition is cleared, that is, when the application is
  340. * able to send more messages.
  341. *
  342. * We expect the application to configure a high water-mark message count,
  343. * which is checked via getNonAckedMessageCount(). When the high water-mark
  344. * is exceeded, the application should install a callback via this method
  345. * to be notified when to start to send new messages.
  346. *
  347. * @param {number} count The low water-mark count. It is an error to pass
  348. * a non-positive value.
  349. * @param {!function()} callback The call back to notify the application
  350. * when NonAckedMessageCount is below the specified low water-mark count.
  351. * Any previously registered callback is cleared. This new callback will
  352. * be cleared once it has been fired, or when the channel is closed or aborted.
  353. */
  354. goog.net.WebChannel.RuntimeProperties.prototype.notifyNonAckedMessageCount =
  355. goog.abstractMethod;
  356. /**
  357. * This method registers a callback to handle the commit request sent
  358. * by the server. Commit protocol spec:
  359. * https://github.com/bidiweb/webchannel/blob/master/commit.md
  360. *
  361. * @param {function(!Object)} callback The callback will take an opaque
  362. * commitId which needs be passed back to the server when an ack-commit
  363. * response is generated by the client application, via ackCommit().
  364. */
  365. goog.net.WebChannel.RuntimeProperties.prototype.onCommit = goog.abstractMethod;
  366. /**
  367. * This method is used by the application to generate an ack-commit response
  368. * for the given commitId. Commit protocol spec:
  369. * https://github.com/bidiweb/webchannel/blob/master/commit.md
  370. *
  371. * @param {!Object} commitId The commitId which denotes the commit request
  372. * from the server that needs be ack'ed.
  373. */
  374. goog.net.WebChannel.RuntimeProperties.prototype.ackCommit = goog.abstractMethod;
  375. /**
  376. * @return {number} The last HTTP status code received by the channel.
  377. */
  378. goog.net.WebChannel.RuntimeProperties.prototype.getLastStatusCode =
  379. goog.abstractMethod;
  380. /**
  381. * A request header to indicate to the server the messaging protocol
  382. * each HTTP message is speaking.
  383. *
  384. * @type {string}
  385. */
  386. goog.net.WebChannel.X_CLIENT_PROTOCOL = 'X-Client-Protocol';
  387. /**
  388. * The value for x-client-protocol when the messaging protocol is WebChannel.
  389. *
  390. * @type {string}
  391. */
  392. goog.net.WebChannel.X_CLIENT_PROTOCOL_WEB_CHANNEL = 'webchannel';
  393. /**
  394. * A response header for the server to signal the wire-protocol that
  395. * the browser establishes with the server (or proxy), e.g. "spdy" (aka http/2)
  396. * "quic". This information avoids the need to use private APIs to decide if
  397. * HTTP requests are multiplexed etc.
  398. *
  399. * @type {string}
  400. */
  401. goog.net.WebChannel.X_CLIENT_WIRE_PROTOCOL = 'X-Client-Wire-Protocol';
  402. /**
  403. * A response header for the server to send back the HTTP session id as part of
  404. * the initial handshake. The value of the HTTP session id is opaque to the
  405. * WebChannel protocol.
  406. *
  407. * @type {string}
  408. */
  409. goog.net.WebChannel.X_HTTP_SESSION_ID = 'X-HTTP-Session-Id';