message_bus 4.3.1 → 4.3.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -34,8 +34,23 @@ beforeEach(function () {
34
34
  this.readyState = 4
35
35
  this.responseText = encodeChunks(this, spec.responseChunks);
36
36
  this.status = spec.responseStatus;
37
- if (this.onprogress){ this.onprogress(); }
38
- this.onreadystatechange()
37
+
38
+ spec.requestStarted?.();
39
+
40
+ const complete = () => {
41
+ if(this.statusText === "abort"){
42
+ return;
43
+ }
44
+ this.onprogress?.();
45
+ this.onreadystatechange();
46
+ }
47
+
48
+ if(spec.delayResponsePromise){
49
+ spec.delayResponsePromise.then(() => complete())
50
+ spec.delayResponsePromise = null;
51
+ }else{
52
+ complete();
53
+ }
39
54
  }
40
55
 
41
56
  MockedXMLHttpRequest.prototype.open = function(){ }
@@ -43,8 +58,8 @@ beforeEach(function () {
43
58
  MockedXMLHttpRequest.prototype.abort = function(){
44
59
  this.readyState = 4
45
60
  this.responseText = '';
46
- this.statusText = '';
47
- this.status = 400;
61
+ this.statusText = 'abort';
62
+ this.status = 0;
48
63
  this.onreadystatechange()
49
64
  }
50
65
 
@@ -68,6 +83,10 @@ beforeEach(function () {
68
83
  "Content-Type": 'text/plain; charset=utf-8',
69
84
  };
70
85
 
86
+ MessageBus.enableChunkedEncoding = true;
87
+ MessageBus.firstChunkTimeout = 3000;
88
+ MessageBus.retryChunkedAfterRequests = 1;
89
+
71
90
  MessageBus.start();
72
91
  });
73
92
 
@@ -75,7 +94,6 @@ afterEach(function(){
75
94
  MessageBus.stop()
76
95
  MessageBus.callbacks.splice(0, MessageBus.callbacks.length)
77
96
  MessageBus.shouldLongPollCallback = null;
78
- MessageBus.enableChunkedEncoding = true;
79
97
  });
80
98
 
81
99
  window.testMB = function(description, testFn, path, data){
@@ -166,4 +166,63 @@ describe("Messagebus", function () {
166
166
  const nextPollScheduledIn = window.setTimeout.calls.mostRecent().args[1];
167
167
  expect(nextPollScheduledIn).toEqual(MessageBus.minPollInterval);
168
168
  });
169
+
170
+ it("enters don't-chunk-mode if first chunk times out", async function () {
171
+ spyOn(this.MockedXMLHttpRequest.prototype, "send").and.callThrough();
172
+ spyOn(
173
+ this.MockedXMLHttpRequest.prototype,
174
+ "setRequestHeader"
175
+ ).and.callThrough();
176
+
177
+ let resolveFirstResponse;
178
+ this.delayResponsePromise = new Promise(
179
+ (resolve) => (resolveFirstResponse = resolve)
180
+ );
181
+ MessageBus.firstChunkTimeout = 50;
182
+
183
+ await new Promise((resolve) => MessageBus.subscribe("/test", resolve));
184
+ resolveFirstResponse();
185
+
186
+ const calls =
187
+ this.MockedXMLHttpRequest.prototype.setRequestHeader.calls.all();
188
+
189
+ const dontChunkCalls = calls.filter((c) => c.args[0] === "Dont-Chunk");
190
+ expect(dontChunkCalls.length).toEqual(1);
191
+ });
192
+
193
+ it("doesn't enter don't-chunk-mode if aborted before first chunk", async function () {
194
+ spyOn(
195
+ this.MockedXMLHttpRequest.prototype,
196
+ "setRequestHeader"
197
+ ).and.callThrough();
198
+
199
+ this.delayResponsePromise = new Promise(() => {});
200
+ MessageBus.firstChunkTimeout = 300;
201
+
202
+ const requestWasStarted = new Promise(
203
+ (resolve) => (this.requestStarted = resolve)
204
+ );
205
+
206
+ // Trigger request
207
+ const subscribedPromise = new Promise((resolve) =>
208
+ MessageBus.subscribe("/test", resolve)
209
+ );
210
+
211
+ await requestWasStarted;
212
+
213
+ // Change subscription (triggers an abort and re-poll)
214
+ MessageBus.subscribe("/test2", () => {});
215
+
216
+ // Wait for stuff to settle
217
+ await subscribedPromise;
218
+
219
+ // Wait 300ms to ensure dontChunk timeout has passed
220
+ await new Promise((resolve) => setTimeout(resolve, 300));
221
+
222
+ const calls =
223
+ this.MockedXMLHttpRequest.prototype.setRequestHeader.calls.all();
224
+
225
+ const dontChunkCalls = calls.filter((c) => c.args[0] === "Dont-Chunk");
226
+ expect(dontChunkCalls.length).toEqual(0);
227
+ });
169
228
  });
@@ -99,6 +99,12 @@ describe MessageBus::Client do
99
99
  chunk2.length.must_equal 0
100
100
  end
101
101
 
102
+ it "does not raise an error when trying to write a message to a closed client using chunked encoding" do
103
+ @client.use_chunked = true
104
+ assert(@client.closed?)
105
+ @client << MessageBus::Message.new(1, 1, "/test", "test")
106
+ end
107
+
102
108
  it "does not bleed data across sites" do
103
109
  @client.site_id = "test"
104
110
 
@@ -205,10 +205,11 @@
205
205
  return handle_progress(payload, endChunk + separator.length);
206
206
  };
207
207
 
208
+ var chunkedTimeout;
208
209
  var disableChunked = function () {
209
210
  if (me.longPoll) {
210
211
  me.longPoll.abort();
211
- chunkedBackoff = 30;
212
+ chunkedBackoff = me.retryChunkedAfterRequests;
212
213
  }
213
214
  };
214
215
 
@@ -235,9 +236,9 @@
235
236
  chunked: chunked,
236
237
  onProgressListener: function (xhr) {
237
238
  var position = 0;
238
- // if it takes longer than 3000 ms to get first chunk, we have some proxy
239
- // this is messing with us, so just backoff from using chunked for now
240
- var chunkedTimeout = setTimeout(disableChunked, 3000);
239
+ // if it takes longer than firstChunkTimeout to get first chunk, there may be a proxy
240
+ // buffering the response. Switch to non-chunked long-polling mode.
241
+ chunkedTimeout = setTimeout(disableChunked, me.firstChunkTimeout);
241
242
  return (xhr.onprogress = function () {
242
243
  clearTimeout(chunkedTimeout);
243
244
  if (
@@ -269,6 +270,7 @@
269
270
  }
270
271
  },
271
272
  error: function (xhr, textStatus) {
273
+ clearTimeout(chunkedTimeout);
272
274
  if (xhr.status === 429) {
273
275
  var tryAfter =
274
276
  parseInt(
@@ -364,6 +366,8 @@
364
366
  clientId: clientId,
365
367
  alwaysLongPoll: false,
366
368
  shouldLongPollCallback: undefined,
369
+ firstChunkTimeout: 3000,
370
+ retryChunkedAfterRequests: 30,
367
371
  baseUrl: baseUrl,
368
372
  headers: {},
369
373
  ajax: typeof jQuery !== "undefined" && jQuery.ajax,
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: message_bus
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.3.1
4
+ version: 4.3.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sam Saffron
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-01-06 00:00:00.000000000 Z
11
+ date: 2023-06-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack