diff --git a/.gitignore b/.gitignore index 27106d2..e7602b7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,8 @@ .project + +/.packages +/.pub packages +/pubspec.lock +/coverage \ No newline at end of file diff --git a/README.md b/README.md index ccee3ad..cb53970 100644 --- a/README.md +++ b/README.md @@ -11,4 +11,21 @@ presents them through WebSocket-like abstractions. SockJS is intended to work for all modern browsers and in environments which don't support WebSocket protocol, for example behind restrictive -corporate proxies. \ No newline at end of file +corporate proxies. + +## Development + +### Dependencies +``` +$ pub get && npm install +``` + +### Tests +``` +$ pub run dart_dev test --integration +``` + +### Coverage +``` +$ pub run dart_dev coverage --integration +``` \ No newline at end of file diff --git a/lib/sockjs_client.dart b/lib/sockjs_client.dart index 6298b20..ddd81b7 100644 --- a/lib/sockjs_client.dart +++ b/lib/sockjs_client.dart @@ -1,6 +1,6 @@ library sockjs_client; -import "dart:html"; +import "dart:html" as html; import "dart:convert"; import "dart:async"; import "dart:js"; @@ -25,7 +25,7 @@ const OPEN = 1; const CLOSING = 2; const CLOSED = 3; -typedef TransformFactory(Client client, String transUrl, [String baseUrl]); +typedef TransformFactory(Client client, String transUrl, {String baseUrl, bool noCredentials}); class Protocol { TransformFactory create; diff --git a/lib/src/ajax.dart b/lib/src/ajax.dart index 4ca9843..5917091 100644 --- a/lib/src/ajax.dart +++ b/lib/src/ajax.dart @@ -6,21 +6,21 @@ class StatusEvent extends event.Event { StatusEvent(String type, [this.status = 0, this.text = ""]) : super(type); } -typedef AbstractXHRObject AjaxObjectFactory(String method, String baseUrl, [payload]); +typedef AbstractXHRObject AjaxObjectFactory(String method, String baseUrl, {bool noCredentials, payload}); class AbstractXHRObject extends Object with event.Emitter { - HttpRequest xhr; + html.HttpRequest xhr; StreamSubscription changeSubscription; Stream get onChunk => this["chunk"]; Stream get onFinish => this["finish"]; Stream get onTimeout => this["timeout"]; - _start(method, url, payload, {noCredentials: false, headers}) { + _start(method, url, payload, {bool noCredentials: false, headers}) { try { - xhr = new HttpRequest(); + xhr = new html.HttpRequest(); } catch(x) {}; if ( xhr == null ) { @@ -61,7 +61,7 @@ class AbstractXHRObject extends Object with event.Emitter { xhr.send(payload); } - _readyStateHandler(Event evt) { + _readyStateHandler(html.Event evt) { switch (xhr.readyState) { case 3: var text, status; @@ -106,22 +106,22 @@ class AbstractXHRObject extends Object with event.Emitter { } class XHRCorsObject extends AbstractXHRObject { - XHRCorsObject(method, url, payload, {noCredentials, headers} ) { - Timer.run(() =>_start(method, url, payload, noCredentials: false)); + XHRCorsObject(method, url, {headers, noCredentials, payload}) { + Timer.run(() =>_start(method, url, payload, noCredentials: noCredentials != null ? noCredentials : false)); } } class XHRLocalObject extends AbstractXHRObject { - XHRLocalObject (method, url, payload, {noCredentials, headers}) { - Timer.run(() =>_start(method, url, payload, noCredentials: true)); + XHRLocalObject(method, url, {headers, noCredentials, payload}) { + Timer.run(() =>_start(method, url, payload, noCredentials: noCredentials != null ? noCredentials : true)); } } -XHRLocalObjectFactory(method, baseUrl, [payload]) => new XHRLocalObject(method, baseUrl, payload); +XHRLocalObjectFactory(method, baseUrl, {bool noCredentials, payload}) => new XHRLocalObject(method, baseUrl, noCredentials: noCredentials, payload: payload); -XHRCorsObjectFactory(method, baseUrl, [payload]) => new XHRCorsObject(method, baseUrl, payload); +XHRCorsObjectFactory(method, baseUrl, {bool noCredentials, payload}) => new XHRCorsObject(method, baseUrl, noCredentials: noCredentials, payload: payload); // 1. Is natively via XHR // 2. Is natively via XDR diff --git a/lib/src/client.dart b/lib/src/client.dart index 43b0c9a..2d34d88 100644 --- a/lib/src/client.dart +++ b/lib/src/client.dart @@ -33,6 +33,8 @@ class Client extends Object with event.Emitter { num roundTrips; num timeout; + bool noCredentials; + var _ir; var _transport = null; @@ -42,6 +44,7 @@ class Client extends Object with event.Emitter { this.debug: false, this.protocolsWhitelist, this.info, + this.noCredentials: false, this.rtt: 0, this.server, this.roundTrips, @@ -70,6 +73,22 @@ class Client extends Object with event.Emitter { Stream get onClose => this["close"]; Stream get onHeartbeat => this["heartbeat"]; + void close([int code, String reason]) { + if (_transport != null) { + if (_transport is WebSocketTransport) { + _transport.doClose(code, reason); + } else if (_transport is XhrStreamingTransport) { + if (code == null) { + code = 0; + } + if (reason == null) { + reason = ''; + } + _didClose(code, reason); + } + } + } + send(data) { if (readyState == CONNECTING) { throw 'INVALID_STATE_ERR'; @@ -199,11 +218,11 @@ class Client extends Object with event.Emitter { // the `head`? if (PROTOCOLS.containsKey(protocol) && PROTOCOLS[protocol].needBody && - ( (document.body == null) || (document.readyState != null && document.readyState != 'complete')) + ( (html.document.body == null) || (html.document.readyState != null && html.document.readyState != 'complete')) ) { _protocols.insert(0, protocol); this.protocol = 'waiting-for-load'; - document.onLoad.listen( (_) => _tryNextProtocol()); + html.document.onLoad.listen( (_) => _tryNextProtocol()); return true; } @@ -234,7 +253,7 @@ class Client extends Object with event.Emitter { var connid = utils.random_string(8); var trans_url = "$_baseUrl/$server/$connid"; _debug('Opening transport: $protocol url:$trans_url RTO:$rto roundTrips:$roundTrips timeout:$to'); - _transport = PROTOCOLS[protocol].create(this, trans_url, _baseUrl); + _transport = PROTOCOLS[protocol].create(this, trans_url, baseUrl: _baseUrl, noCredentials: noCredentials); return true; } } diff --git a/lib/src/info.dart b/lib/src/info.dart index 389d711..5c1db15 100644 --- a/lib/src/info.dart +++ b/lib/src/info.dart @@ -12,7 +12,7 @@ class Info { origins = json["origins"]; cookieNeeded = json["cookie_needed"]; entropy = json["entropy"]; - nullOrigin = (document.domain == null); + nullOrigin = (html.document.domain == null); } } @@ -84,8 +84,8 @@ class AjaxInfoReceiver extends InfoReceiver { class InfoReceiverIframe extends InfoReceiver { InfoReceiverIframe(base_url) : super._() { - if(document.body == null) { - document.onLoad.listen((_) => go()); + if(html.document.body == null) { + html.document.onLoad.listen((_) => go()); } else { go(); } diff --git a/lib/src/transport/polling.dart b/lib/src/transport/polling.dart index 852cc9a..6749d41 100644 --- a/lib/src/transport/polling.dart +++ b/lib/src/transport/polling.dart @@ -8,13 +8,14 @@ class Polling { AjaxObjectFactory xhrFactory; XhrReceiver poll; bool pollIsClosing = false; + bool noCredentials; - Polling(this.ri, this.receiverFactory, this.recvUrl, this.xhrFactory) { + Polling(this.ri, this.receiverFactory, this.recvUrl, this.xhrFactory, {bool this.noCredentials}) { _scheduleRecv(); } _scheduleRecv() { - poll = receiverFactory(recvUrl, xhrFactory); + poll = receiverFactory(recvUrl, xhrFactory, noCredentials: noCredentials); var msg_counter = 0; var msgHandler = (e) { msg_counter += 1; diff --git a/lib/src/transport/receiver-xhr.dart b/lib/src/transport/receiver-xhr.dart index 812b050..d78e8a1 100644 --- a/lib/src/transport/receiver-xhr.dart +++ b/lib/src/transport/receiver-xhr.dart @@ -4,10 +4,10 @@ part of sockjs_client; AbstractXHRObject xo = null; - XhrReceiver(url, AjaxObjectFactory xhrFactory) { + XhrReceiver(url, AjaxObjectFactory xhrFactory, {bool noCredentials}) { var buf_pos = 0; - xo = xhrFactory('POST', url); + xo = xhrFactory('POST', url, noCredentials: noCredentials); xo.onChunk.listen((e){ if (e.status != 200) return; while (true) { @@ -36,4 +36,4 @@ part of sockjs_client; } } -XhrReceiverFactory(String recvUrl, AjaxObjectFactory xhrFactory) => new XhrReceiver(recvUrl, xhrFactory); +XhrReceiverFactory(String recvUrl, AjaxObjectFactory xhrFactory, {bool noCredentials}) => new XhrReceiver(recvUrl, xhrFactory, noCredentials: noCredentials); diff --git a/lib/src/transport/sender.dart b/lib/src/transport/sender.dart index 2b4b771..69870b8 100644 --- a/lib/src/transport/sender.dart +++ b/lib/src/transport/sender.dart @@ -66,18 +66,18 @@ class BufferedSender { // postMessage communication */ class JsonPGenericSender { - FormElement _sendForm = null; - TextAreaElement _sendArea = null; + html.FormElement _sendForm = null; + html.TextAreaElement _sendArea = null; var completed; JsonPGenericSender(url, payload, callback) { - FormElement form; - TextAreaElement area; + html.FormElement form; + html.TextAreaElement area; if (_sendForm == null) { - form = _sendForm = new Element.tag('form'); - area = _sendArea = new Element.tag('textarea'); + form = _sendForm = new html.Element.tag('form'); + area = _sendArea = new html.Element.tag('textarea'); area.name = 'd'; form.style.display = 'none'; form.style.position = 'absolute'; @@ -85,7 +85,7 @@ class JsonPGenericSender { form.enctype = 'application/x-www-form-urlencoded'; form.acceptCharset = "UTF-8"; form.children.add(area); - document.body.children.add(form); + html.document.body.children.add(form); } form = _sendForm; area = _sendArea; @@ -93,12 +93,12 @@ class JsonPGenericSender { form.target = id; form.action = '$url/jsonp_send?i=$id'; - IFrameElement iframe; + html.IFrameElement iframe; try { // ie6 dynamic iframes with target="" support (thanks Chris Lambacher) - iframe = new Element.html('