This pull request is regarding the issue of infinite loop in SockJS library for xhr-polling and xhr-streaming transport.
When Spring sends unformatted frame SockJsFrame.closeFrameGoAway() without ending \n like c[1000, "Go Away!"] then SockJS library is unable to parse it correctly and to recognise it as native close frame. Instead of that SockJS treats it as just plain text.
xhr.js file has next method to parse inbound text message:
XhrReceiver.prototype._chunkHandler = function(status, text) {
debug('_chunkHandler', status);
if (status !== 200 || !text) {
return;
}
for (var idx = -1; ; this.bufferPosition += idx + 1) {
var buf = text.slice(this.bufferPosition);
idx = buf.indexOf('\n');
if (idx === -1) {
break;
}
var msg = buf.slice(0, idx);
if (msg) {
debug('message', msg);
this.emit('message', msg);
}
}
};
That method expects \n at the end of the SockJS text frame.
But in case of "Connection already closed (but not removed yet) for sessionId" Spring Framework sends unformatted SockJsFrame.closeFrameGoAway() without ending \n. That leads to infinite loop at SockJS library because it is unable to parse that frame.
This fix is about to add formatting for SockJsFrame.closeFrameGoAway() before sending to the client.
Some reported issues: https://github.com/sockjs/sockjs-client/issues/418 https://github.com/sockjs/sockjs-client/issues/308 https://stackoverflow.com/questions/37030416/sockjs-infinite-xhr-streaming-calls-after-reconnect/70957300#70957300
Comment From: angusoid
This one caused me some headaches and made my userbase a DDoS army.
Good job for figuring this one out!
Comment From: rstoyanchev
Thanks for figuring out the root cause!
Comment From: ankitpec72
Thank you for figuring this out. @zbykovskyi I am struggling with the same issues since last 3 Months. When can we expect the new release?
Cheers!!
Comment From: zbykovskyi
Thank you for figuring this out. @zbykovskyi I am struggling with the same issues since last 3 Months. When can we expect the new release?
Cheers!!
You can put files with fix locally to be the first in your classpath to override original files for now until official bugfix will be released
Cheers!
Comment From: radonaldson54
@zbykovskyi Can you please give an example of the classpath for this and the file to include first? We are trying to fix here and would really appreciate the help :-) Thanks!
Comment From: ankitpec72
Thank you for figuring this out. @zbykovskyi I am struggling with the same issues since last 3 Months. When can we expect the new release? Cheers!!
You can put files with fix locally to be the first in your classpath to override original files for now until official bugfix will be released
Cheers!
You are our savior. Thanks a lot :)
Comment From: zbykovskyi
@zbykovskyi Can you please give an example of the classpath for this and the file to include first? We are trying to fix here and would really appreciate the help :-) Thanks!
Copy the next original Spring files and put them in your project`s codebase in the same package:
- org.springframework.web.socket.sockjs.transport.session.AbstractHttpSockJsSession.java
- org.springframework.web.socket.sockjs.transport.handler.AbstractHttpSendingTransportHandler.java
Then apply patch from current pull request and compile your project. These fixed files will be before original files in the classpath. After official release just remove these files.
Comment From: hatvqd
anyone met this bug again? I just implemented base on Spring Boot 2.6.6, sockjs 1.6.1 and still got that bug sometime. I try to simulate on my local case by case or in product by my account case by case but can not
Comment From: zbykovskyi
anyone met this bug again? I just implemented base on Spring Boot 2.6.6, sockjs 1.6.1 and still got that bug sometime. I try to simulate on my local case by case or in product by my account case by case but can not
Could you add more details on your issue? What is the body of http POST requests and how to reproduce that behaviour?