iframe-htmlfile re-opening connections

603 views
Skip to first unread message

Tim Fox

unread,
Dec 14, 2012, 10:21:34 AM12/14/12
to soc...@googlegroups.com
We have an issue when using the iframe-htmlfile transport in Vert.x - not sure if it is an issue in the sockjs client or the Vert.x implementation....

It happens on all versions of the sockjs client I have tested (up to 0.3.4)

Basically....

I set protocols_whitelist to contain only iframe-htmlfile, so we force that transport.

The client then creates a SockJS socket, and sends a message on it.

All good so far.

The connection is then not used for some time. After 5 seconds (this is default session timeout in Vert.x), Vert.x closes the connection.

The client then attempts to send another message on the same connection.

This causes the sockjs client to create a new connection (i.e. it sends a request with a uri like: /eventbus/903/1tcjituw/htmlfile?c=_jp.avtmjdz)

The message is sent ok.

The connection is unused again for more than 5 seconds so Vert.x times out this new connection.

This time the sockjs client does not attempt to recreate the connection, so the client is left with a dead connection.

Any ideas?

Is the Vert.x behaviour of timing out connection after 5 seconds correct? If not, what should it do?

Thanks.

Serge S. Koval

unread,
Dec 14, 2012, 10:50:35 AM12/14/12
to timv...@gmail.com, soc...@googlegroups.com
Hi,

iframe-htmlfile is streaming transport and default polling transport
logic should not apply to streaming transports. So, there's no need to
close session after 5 seconds of inactivity, because client will only
come back if it has something to send to the server.

Serge.

Tim Fox

unread,
Dec 14, 2012, 10:52:35 AM12/14/12
to soc...@googlegroups.com, timv...@gmail.com
Thanks Serge,

Are there any docs that say what "default streaming/polling transport behaviour" is? This is what I bang my head against with SockJS.

Tim Fox

unread,
Dec 14, 2012, 11:04:11 AM12/14/12
to Serge S. Koval, soc...@googlegroups.com
On 14/12/12 15:50, Serge S. Koval wrote:
> Hi,
>
> iframe-htmlfile is streaming transport and default polling transport
> logic should not apply to streaming transports. So, there's no need to
> close session after 5 seconds of inactivity, because client will only
> come back if it has something to send to the server.

Also... if sessions don't get auto-expired after a timeout, when do they
expire? If they don't expire surely we have a memory leak?
>
> Serge.
>
> On Fri, Dec 14, 2012 at 5:21 PM, Tim Fox <timv...@gmail.com> wrote:
>> We have an issue when using the iframe-htmlfile transport in Vert.x - not
>> sure if it is an issue in the sockjs client or the Vert.x implementation....
>>
>> It happens on all versions of the sockjs client I have tested (up to 0.3.4)
>>
>> Basically....
>>
>> I set protocols_whitelist to contain only iframe-htmlfile, so we force that
>> transport.
>>
>> The client then creates a SockJS socket, and sends a message on it.
>>
>> All good so far.
>>
>> The connection is then not used for some time. After 5 seconds (this is
>> default session timeout in Vert.x), Vert.x closes the connection.
>>
>> The client then attempts to send another message on the same connection.
>>
>> This causes the sockjs client to create a new connection (i.e. it sends a
>> request with a uri like: /eventbus/903/1tcjituw/htmlfile?c=_jp.avtmjdz)
>>
>> The message is sent ok.
>>
>> The connection is unused again for more than 5 seconds so Vert.x times out
>> this new connection.
>>
>> This time the sockjs client does not attempt to recreate the connection, so
>> the client is left with a dead connection.
>>
>> Any ideas?
>>
>> Is the Vert.x behaviour of timing out connection after 5 seconds correct? If
>> not, what should it do?
>>
>> Thanks.


--
Tim Fox

Vert.x - effortless polyglot asynchronous application development
http://vertx.io
twitter:@timfox

Serge S. Koval

unread,
Dec 14, 2012, 11:04:43 AM12/14/12
to timv...@gmail.com, soc...@googlegroups.com
Uh, I will try to look it up.

In a nutshell, streaming transport uses one persistent outgoing HTTP
connection (with transfer-encoding: chunked) to send data from the
server and bunch of short-lived connections from the client.

Whenever, server wants to send something, it will send data over
existing outgoing connection. If there's more than 128 KB (by default)
of data sent over connection, server should close connection and
client will reconnect with another streaming connection.

In terms of logic - you can use polling session timeout, but start
countdown after long-lived connection was closed by the server. If
client didn't come back in 5 seconds, you can close the session.

Just in case, there are 3 different streaming transports in SockJS:
xhr-streaming, eventsource and htmlfile. All three should behave the
same (except of the wire protocol).

Client tests should cover all three.

Serge.

Serge S. Koval

unread,
Dec 14, 2012, 11:05:41 AM12/14/12
to Tim Fox, soc...@googlegroups.com
They expire if:
1. Connection was dropped (networking error, etc)
2. If client didn't come back in 5s after server decided to "refresh"
long lived connection.

Serge.

Tim Fox

unread,
Dec 14, 2012, 11:11:42 AM12/14/12
to soc...@googlegroups.com, timv...@gmail.com
I so wish this stuff was written down somewhere.

Fugiman

unread,
Dec 14, 2012, 11:12:52 AM12/14/12
to soc...@googlegroups.com, timv...@gmail.com

Tim Fox

unread,
Dec 14, 2012, 11:17:45 AM12/14/12
to Fugiman, soc...@googlegroups.com
It is not.

A set of tests != a spec

Any, in any case, Vert.x currently passes all the sockjs protocol tests,
even though the current session closing behaviour for streaming
transports is wrong.

Serge S. Koval

unread,
Dec 14, 2012, 11:20:52 AM12/14/12
to timv...@gmail.com, Fugiman, soc...@googlegroups.com
Looks like there's problem with the tests - they should do at least
two POSTs for streaming transports and receive response over same
connection to detect this kind of error.

Overall, I will try to contribute some information how different
transports work and what to expect to the sockjs-protocol.

Serge.

Tim Fox

unread,
Dec 14, 2012, 11:32:33 AM12/14/12
to Serge S. Koval, Fugiman, soc...@googlegroups.com
On 14/12/12 16:20, Serge S. Koval wrote:
> Looks like there's problem with the tests - they should do at least
> two POSTs for streaming transports and receive response over same
> connection to detect this kind of error.
>
> Overall, I will try to contribute some information how different
> transports work and what to expect to the sockjs-protocol.

I think this would be a huge plus to the project, and would be a
differentiator over socket.io.

I like SockJS and want to continue using it, but I've wasted so much
time over the last year or more asking the same old questions about what
is the correct server behaviour and getting the same old answers of
"look at the tests" or "look at the sockjs-node implementation". Those
are not good answers.

A little document somewhere that explains, for each transport - what is
the session lifecycle; what is the connection lifecycle; when sessions /
connections are timed out / closed etc would be worth its weight in gold.

Right now I'm getting tired of banging my head against this brick wall,
and I've been considering other options than SockJS - unfortunately (or
fortunately for SockJS) there aren't many... I've even considered
writing my own - at least then I would know how it is supposed to work! ;)

Marek Majkowski

unread,
Dec 14, 2012, 12:33:00 PM12/14/12
to timv...@gmail.com, Serge S. Koval, Fugiman, soc...@googlegroups.com
On Fri, Dec 14, 2012 at 4:32 PM, Tim Fox <timv...@gmail.com> wrote:
> I think this would be a huge plus to the project, and would be a
> differentiator over socket.io.
>
> I like SockJS and want to continue using it, but I've wasted so much time
> over the last year or more asking the same old questions about what is the
> correct server behaviour and getting the same old answers of "look at the
> tests" or "look at the sockjs-node implementation". Those are not good
> answers.
>
> A little document somewhere that explains, for each transport - what is the
> session lifecycle; what is the connection lifecycle; when sessions /
> connections are timed out / closed etc would be worth its weight in gold.
>
> Right now I'm getting tired of banging my head against this brick wall, and
> I've been considering other options than SockJS - unfortunately (or
> fortunately for SockJS) there aren't many... I've even considered writing my
> own - at least then I would know how it is supposed to work! ;)

Tim,

You started on asking a valid technical question, now you started
bashing SockJS. Please make up your mind.

Marek

Tim Fox

unread,
Dec 14, 2012, 12:56:41 PM12/14/12
to soc...@googlegroups.com, timv...@gmail.com, Serge S. Koval, Fugiman
I'm not bashing SockJS, I have done probably more than anyone in promoting SockJS in the JVM world.

However I find myself continually coming back to the same issue, and it's incredibly frustrating... The lack of a specification.

Please take this as constructive criticism.

Serge S. Koval

unread,
Dec 14, 2012, 12:57:10 PM12/14/12
to timv...@gmail.com, soc...@googlegroups.com
Another thing that came to my mind: if it was graceful disconnection
by the server, client _should_ come back to the server for more data.

So, if server implements streaming transport as polling (will close
connection after it sent something), SockJS should work, but not as
efficiently as it should. Probably this explains why this issue was
unnoticed for long time, but does not explain why htmlfile did not
work.

Few questions:
1. Can you try with xhr-streaming and current vert.x logic?
2. What was the IE version in your tests?
3. Can you run QUnit tests against vert.x server?

Thanks,
Serge.

Marek Majkowski

unread,
Dec 14, 2012, 1:15:30 PM12/14/12
to timv...@gmail.com, soc...@googlegroups.com
On Fri, Dec 14, 2012 at 3:21 PM, Tim Fox <timv...@gmail.com> wrote:
> The client then attempts to send another message on the same connection.
>
> This causes the sockjs client to create a new connection (i.e. it sends a
> request with a uri like: /eventbus/903/1tcjituw/htmlfile?c=_jp.avtmjdz)

No. In SockJS sending and receiving are two independent things.
It is not true that sending a message from sockjs-client has anything to
do with the long-polling / streaming http requests (like /htmlfile).

Sending a message in sockjs-client causes a browser to send
data to /send URL. It does not affect long-polling / streaming requests.

Your server should not close /htmlfile or /xhr_streaming requests after
5 seconds. Streaming http requests are not time-bound. They should
be closed only when:
a) server application calls close() (you need to send close frame
before closing)
b) 128KiB (or other number, customized by user) of data is sent
over a single request.

(you should send "h" frame every 25 seconds on /htmlfile or /xhr_streaming,
to keep the connection alive in case of nasty load balancers)

But all this may be irrelevant for this particular issue. SockJS-client
will automatically reconnect if server closes a streaming request.
Client responsibility is to reconnect to this /htmlfile request
and to do it promptly (5 seconds).

The 5 seconds timeout is for the situation when server closes
a long-polling or streaming request _and_ doesn't hear the
client to get back within 5 seconds. At this point, server
has no clue where the client had gone, so it can assume
the session is closed.

I think the easiest way to proceed is to do two things:
a) please try running qunit tests against vert.x
(like this: http://sockjs.cloudfoundry.com/tests-qunit.html )
b) please create a pcap network dump from the session
you feel went wrong (using wireshark or tcpdump). I may
be able to say something based on that.
(but please make it short, with one recorded session only)

Cheers,
Marek

Tim Fox

unread,
Dec 14, 2012, 1:24:24 PM12/14/12
to Marek Majkowski, soc...@googlegroups.com
On 14/12/2012 18:15, Marek Majkowski wrote:
> On Fri, Dec 14, 2012 at 3:21 PM, Tim Fox <timv...@gmail.com> wrote:
>> The client then attempts to send another message on the same connection.
>>
>> This causes the sockjs client to create a new connection (i.e. it sends a
>> request with a uri like: /eventbus/903/1tcjituw/htmlfile?c=_jp.avtmjdz)
> No. In SockJS sending and receiving are two independent things.
> It is not true that sending a message from sockjs-client has anything to
> do with the long-polling / streaming http requests (like /htmlfile).
>
> Sending a message in sockjs-client causes a browser to send
> data to /send URL. It does not affect long-polling / streaming requests.
>
> Your server should not close /htmlfile or /xhr_streaming requests after
> 5 seconds. Streaming http requests are not time-bound. They should
> be closed only when:
> a) server application calls close() (you need to send close frame
> before closing)
> b) 128KiB (or other number, customized by user) of data is sent
> over a single request.

What if the client just disappears at this point? The session will be
left on the server. With no timeout wouldn't that lead to a memory leak?
>
> (you should send "h" frame every 25 seconds on /htmlfile or /xhr_streaming,
> to keep the connection alive in case of nasty load balancers)
>
> But all this may be irrelevant for this particular issue. SockJS-client
> will automatically reconnect if server closes a streaming request.
> Client responsibility is to reconnect to this /htmlfile request
> and to do it promptly (5 seconds).

Right.. I'm seeing it reconnect once, but if the second connection is
closed by the server, it doesn't seem to reconnect again.
>
> The 5 seconds timeout is for the situation when server closes
> a long-polling or streaming request _and_ doesn't hear the
> client to get back within 5 seconds. At this point, server
> has no clue where the client had gone, so it can assume
> the session is closed.
>
> I think the easiest way to proceed is to do two things:
> a) please try running qunit tests against vert.x
> (like this: http://sockjs.cloudfoundry.com/tests-qunit.html )

They all pass. I always run all the qunit + protocol tests before any
vert.x release.

Tim Fox

unread,
Dec 14, 2012, 1:26:16 PM12/14/12
to Serge S. Koval, soc...@googlegroups.com
On 14/12/2012 17:57, Serge S. Koval wrote:
> Another thing that came to my mind: if it was graceful disconnection
> by the server, client _should_ come back to the server for more data.
>
> So, if server implements streaming transport as polling (will close
> connection after it sent something), SockJS should work, but not as
> efficiently as it should. Probably this explains why this issue was
> unnoticed for long time, but does not explain why htmlfile did not
> work.

Right, this is what I would expect but it seems the client only tries to
reconnect once.
>
> Few questions:
> 1. Can you try with xhr-streaming and current vert.x logic?
> 2. What was the IE version in your tests?

This doesn't seem to be browser specific - I get the same behaviour on
IE9 and Chrome (recent version - can't remember exact one)
> 3. Can you run QUnit tests against vert.x server?

All tests pass

Marek Majkowski

unread,
Dec 14, 2012, 1:55:00 PM12/14/12
to Tim Fox, soc...@googlegroups.com
On Fri, Dec 14, 2012 at 6:24 PM, Tim Fox <timv...@gmail.com> wrote:
> On 14/12/2012 18:15, Marek Majkowski wrote:
>> Your server should not close /htmlfile or /xhr_streaming requests after
>> 5 seconds. Streaming http requests are not time-bound. They should
>> be closed only when:
>> a) server application calls close() (you need to send close frame
>> before closing)
>> b) 128KiB (or other number, customized by user) of data is sent
>> over a single request.
>
> What if the client just disappears at this point? The session will be left
> on the server. With no timeout wouldn't that lead to a memory leak?

As I've written:

>> The 5 seconds timeout is for the situation when server closes
>> a long-polling or streaming request _and_ doesn't hear the
>> client to get back within 5 seconds. At this point, server
>> has no clue where the client had gone, so it can assume
>> the session is closed.

this is when 5 seconds thing kick. Basically - if a server
doesn't have a long-polling connection for a particular
session for longer than 5 seconds, it is free to
assume the session got closed and forget about it.

But that does not mean the server must close
a long polling / streaming http request every 5 seconds.

>> (you should send "h" frame every 25 seconds on /htmlfile or
>> /xhr_streaming,
>> to keep the connection alive in case of nasty load balancers)
>>
>> But all this may be irrelevant for this particular issue. SockJS-client
>> will automatically reconnect if server closes a streaming request.
>> Client responsibility is to reconnect to this /htmlfile request
>> and to do it promptly (5 seconds).
>
> Right.. I'm seeing it reconnect once, but if the second connection is closed
> by the server, it doesn't seem to reconnect again.

Does it call 'connection.onclose()' in client? Maybe it thinks the
server died.

> They all pass. I always run all the qunit + protocol tests before any vert.x
> release.

Ah, Cool!

>> b) please create a pcap network dump from the session
>> you feel went wrong (using wireshark or tcpdump). I may
>> be able to say something based on that.
>> (but please make it short, with one recorded session only)

How about the wireshark dump?

I tried to prepare a test replicating your setup - send messages
such long that they hit 128KiB limit and result in /htmlfile request
being closed. Run it like this:
http://localhost:8080/tests-qunit.html?filter=iframe-htmlfile%3A%20large%20download%20for%20Tim
It works for me (running chrome). It probably won't work over
the internet due to loads of data being transferred, but should
work fine locally. I'm not sure what that test proves - probably
nothing, but we'd learn something if it failed for vert.x

diff --git a/tests/html/src/tests.coffee b/tests/html/src/tests.coffee
index 90ef2db..03c782b 100644
--- a/tests/html/src/tests.coffee
+++ b/tests/html/src/tests.coffee
@@ -178,6 +178,36 @@ factor_batch_large = (protocol) ->
return batch_factory_factory(protocol, messages)


+xbatch_factory_factory_amp = (protocol, counter) ->
+ return ->
+ console.log "yes, this test is running!"
+ expect(3 + counter * 2)
+ r = newSockJS('/amplify', protocol)
+ ok(r)
+ sent = 0
+ recv = 0
+ r.onopen = (e) ->
+ ok(true)
+ r.send(''+17)
+ r.send(''+17)
+ sent += 2
+ r.onmessage = (e) ->
+ equals(e.data.length, Math.pow(2, 17), e.data)
+ recv += 1
+ if sent < counter * 2
+ r.send(''+17)
+ r.send(''+17)
+ sent += 2
+ if recv == sent
+ r.close()
+ r.onclose = (e) ->
+ ok(true)
+ start()
+
+xfactor_batch_large_amp = (protocol) ->
+ return xbatch_factory_factory_amp(protocol, 10)
+
+
batch_factory_factory_amp = (protocol, messages) ->
return ->
expect(3 + messages.length)
@@ -303,6 +333,8 @@ test_protocol_messages = (protocol) ->
asyncTest("large message (batch)", factor_batch_large(protocol))
asyncTest("large download", factor_batch_large_amp(protocol))

+ asyncTest("large download for Tim", xfactor_batch_large_amp(protocol))
+
asyncTest("user close", factor_user_close(protocol))
asyncTest("server close", factor_server_close(protocol))

Marek Majkowski

unread,
Dec 14, 2012, 1:58:40 PM12/14/12
to Tim Fox, soc...@googlegroups.com
Addtionally, the best way to replicate what you're talking about it to drop
the `response_limit` for /broadcast service to say 512:

diff --git a/examples/test_server/sockjs_app.js
b/examples/test_server/sockjs_app.js
index 5c77221..73aedd2 100644
--- a/examples/test_server/sockjs_app.js
+++ b/examples/test_server/sockjs_app.js
@@ -81,5 +81,6 @@ exports.install = function(opts, server) {
sjs_close.installHandlers(server, {prefix:'/close'});
sjs_ticker.installHandlers(server, {prefix:'/ticker'});
sjs_amplify.installHandlers(server, {prefix:'/amplify'});
- sjs_broadcast.installHandlers(server, {prefix:'/broadcast'});
+ sjs_broadcast.installHandlers(server, {prefix:'/broadcast',
+ response_limit: 512});
};


And run cursors demo. I deployed it here:
http://sockjs.cloudfoundry.com/example-cursors.html

How to run it:
1) open demo in chrome, select iframe-htmlfile, click connect,
open inspector
2) open it in firefox, click connect and move mouse around

As the response limit is tiny (512 bytes) you will see /htmlfile
requests being respawned automatically pretty often.

Marek

Tim Fox

unread,
Dec 14, 2012, 2:03:40 PM12/14/12
to Marek Majkowski, soc...@googlegroups.com
On 14/12/2012 18:55, Marek Majkowski wrote:
> On Fri, Dec 14, 2012 at 6:24 PM, Tim Fox <timv...@gmail.com> wrote:
>> On 14/12/2012 18:15, Marek Majkowski wrote:
>>> Your server should not close /htmlfile or /xhr_streaming requests after
>>> 5 seconds. Streaming http requests are not time-bound. They should
>>> be closed only when:
>>> a) server application calls close() (you need to send close frame
>>> before closing)
>>> b) 128KiB (or other number, customized by user) of data is sent
>>> over a single request.
>> What if the client just disappears at this point? The session will be left
>> on the server. With no timeout wouldn't that lead to a memory leak?
> As I've written:
>
>>> The 5 seconds timeout is for the situation when server closes
>>> a long-polling or streaming request _and_ doesn't hear the
>>> client to get back within 5 seconds. At this point, server
>>> has no clue where the client had gone, so it can assume
>>> the session is closed.
> this is when 5 seconds thing kick. Basically - if a server
> doesn't have a long-polling connection for a particular
> session for longer than 5 seconds, it is free to
> assume the session got closed and forget about it.

But in the case I'm talking about the server hasn't closed anything, so
it's not covered by case a), the client has just disappeared. Also it's
not covered by case b) since < 128kiB of data has been sent. So we have
a session on the server that never gets timed out.

Marek Majkowski

unread,
Dec 14, 2012, 2:06:42 PM12/14/12
to Tim Fox, soc...@googlegroups.com
On Fri, Dec 14, 2012 at 7:03 PM, Tim Fox <timv...@gmail.com> wrote:
> But in the case I'm talking about the server hasn't closed anything, so it's
> not covered by case a), the client has just disappeared. Also it's not
> covered by case b) since < 128kiB of data has been sent. So we have a
> session on the server that never gets timed out.

Like this?
http://sockjs.github.com/sockjs-protocol/sockjs-protocol-0.3.3.html#section-149

Marek

Tim Fox

unread,
Dec 14, 2012, 2:22:05 PM12/14/12
to Marek Majkowski, soc...@googlegroups.com
You mean network error? If a client just disappears from the network you
won't necessarily get a socket error on the server. TCP is a reliable
protocol and this is indistinguishable from packet loss.

Most systems use heartbeats or timeouts to deal with this case... which
is why I'm asking about timeouts.

Shripad K

unread,
Dec 14, 2012, 2:51:30 PM12/14/12
to Tim Fox, Marek Majkowski, SockJS
Marek has explained it perfectly. In the iframe-htmlfile or iframe-eventsource, server will close() the connection as soon as the client leaves. Setting a 5 second timeout is not required. With Transfer-Encoding: Chunked, you create a Unidirectional socket which is used only for sending data from server to client. So that socket will be kept open until the client keeps it open (via a browser tab/window). The moment client closes the tab/window, server recv() == 0 and server close()'s connection (regular TCP stuff). If you are going to place a 5 second timeout, its not longer streaming transport but a polling transport :)

It however does not call the close callback immediately. If for some reason, the client "sees" a disconnection (probably your reverse proxy has a timeout set), the server closes the connection, but does not discard the session information (like session ID etc) for 5 seconds. This opportunity is given for the client should it want to reconnect within 5 seconds. If the client cannot reconnect, the server assumes the client has disconnected and calls the close callback (NOTE: it has already discarded the connection) after the timeout expires.

The only disadvantage of using streaming transport is the 6 connection limit. You can avoid it using CNAMEs but its PITA (especially when dealing with HTTPS).

Shripad K

unread,
Dec 14, 2012, 3:01:15 PM12/14/12
to Tim Fox, Marek Majkowski, SockJS

The 5 second timeout is set only after the connection closes (5 second timeout is not for connection itself -> if you do this then it becomes a polling transport). This 5 second window is given for client to reconnect (should it want to) in case of abrupt disconnection. The server keeps the session info only for these 5 seconds. If the client cannot reconnect within 5 seconds, server discards the session info and calls the close callback.

Shripad K

unread,
Dec 14, 2012, 3:20:00 PM12/14/12
to Tim Fox, SockJS
You should not timeout the connection every 5 seconds for streaming transports. Its similar to websockets but unidirectional (instead of being bidirectional -> so you are only receiving messages on this connection from the server). The connection should be kept open and should be naturally closed by the client (whenever the client closes the tab/window). For sending messages a new connection should be created (AJAX/jsonp), the message is then sent (along with an identifier.. like the session ID of the persistent connection), and the connection is immediately severed.

The real problem arises when you already have 6 persistent connections from browser. If you hit the 6 connection limit, then subsequent AJAX requests for sending messages will not succeed (as you have already used up the 6 max connections). Exception to this is websockets (200 max connections).

 

Thanks.

Tim Fox

unread,
Dec 14, 2012, 3:29:24 PM12/14/12
to Shripad K, Marek Majkowski, SockJS
On 14/12/2012 19:51, Shripad K wrote:
Marek has explained it perfectly. In the iframe-htmlfile or iframe-eventsource, server will close() the connection as soon as the client leaves. Setting a 5 second timeout is not required. With Transfer-Encoding: Chunked, you create a Unidirectional socket which is used only for sending data from server to client. So that socket will be kept open until the client keeps it open (via a browser tab/window). The moment client closes the tab/window, server recv() == 0 and server close()'s connection (regular TCP stuff).

That's fine if the user closes the tab/browser, or even if the browser process dies (since in that case the OS will close the browsers connections), but in the general case, you will not always get notification on the server if a client disappears (e.g. cable is pulled out, or router explodes).

This is just the way TCP works - it's a reliable protocol and this situation is not easily distinguishable from lost packets (the server can't tell if the client has really disappeared or just a lot of packets are being lost). default TCP timeout is really high, so unless you actively heartbeat or timeout sessions on the server, you're going to get memory leaks if you're relying on a network error being reported on the server in order for you to close the session.

Tim Fox

unread,
Dec 14, 2012, 3:31:56 PM12/14/12
to Shripad K, Marek Majkowski, SockJS
This information is great. Between the three of you, you seem to have a great understanding of how a SockJS server is supposed to behave.

Now, what would be even better if one of you could write up that knowledge, and publish it somewhere. Hell, you could even call it a spec. Then I wouldn't have to keep bugging you about the same old issues, which I'm sure isn't much fun for you either :)

Shripad K

unread,
Dec 14, 2012, 3:33:46 PM12/14/12
to Tim Fox, Marek Majkowski, SockJS
That case depends on the TCP Keepalive. By default TCP keepalive is set to 2 hours. So in case the socket enters into a half-open state, the socket will receive close() event after 2 hours (or whatever time you have set). This is handled by the OS and you needn't necessarily have to implement it yourself. If you find the timeout really high then lower it (sysctl is your friend here :) )

Shripad K

unread,
Dec 14, 2012, 3:35:50 PM12/14/12
to Tim Fox, Marek Majkowski, SockJS
Lol to be honest, I read up the SockJS code a lot (its well written compared to other implementations). I like the ws library better than faye (its fast). So i wrote my own D port of Node (like you did vert.x) and wrote a custom websocket implementation (with fallbacks). Drew heavy inspiration from SockJS. But yes a post should be necessary ( maybe howtonode? ).

Tim Fox

unread,
Dec 14, 2012, 3:36:15 PM12/14/12
to Shripad K, Marek Majkowski, SockJS
On 14/12/2012 20:33, Shripad K wrote:
That case depends on the TCP Keepalive. By default TCP keepalive is set to 2 hours.
Yes, like I said, default is really high. You can create a lot of sessions in 2 hours, easily enough for a DoS. That's why most systems heartbeat with timeout.

Shripad K

unread,
Dec 14, 2012, 3:39:18 PM12/14/12
to Tim Fox, Marek Majkowski, SockJS
But you can just lower the TCP timeout.. I don't see a reason to use heartbeat. You'll waste a lot of bandwidth. The regular TCP probes are just 54 bytes in total (even if you set a TCP keepalive of 1 hour and have 1 million persisten connections idling for a month, the total bandwidth usage will be around 15GB). But if you are going to do the heartbeat mechanism at application level, then you are going to append lots of unwanted data to the TCP header at the expense of greater bandwidth usage. (Definitely you have more control over your timeouts... like you can set certain connections with 10 second timeout, while some other with a different duration) But if you are going to set same timeout for all connections, you might as well just let the OS handle it for you. :)

Shripad K

unread,
Dec 14, 2012, 3:49:15 PM12/14/12
to Tim Fox, Marek Majkowski, SockJS
Also NodeJS has a application level keepalive setting where you can set the initial delay per connection (without the need for managing heartbeats):

http://nodejs.org/api/net.html#net_socket_setkeepalive_enable_initialdelay

Else, you can always set global tcp_keepalive_time, tcp_keepalive_intvl and tcp_keepalive_probes values using sysctl (OSX equivalent: net.inet.tcp.keepintvl, net.inet.tcp.keepidle)

Tim Fox

unread,
Dec 14, 2012, 4:04:04 PM12/14/12
to Shripad K, Marek Majkowski, SockJS
So, to summarise (here is my mini spec):

For streaming transports:

The connection can be closed either
a) Unilaterally by the client
b) Because of TCP timeout on the server
c) By the application on the server
d) By the Server SockJS implementation because > 128 KiB has been sent

In either of those cases the server side SockJS impl will start a timeout (default 5 seconds). If the client does not reconnect with the same session id in that time, the session will be removed from the server

For polling transports:

The connection can be closed either
a) Unilaterally by the client (this is normal after each poll)
b) Because of TCP timeout on the server (unlikely but posssible if the poll takes a very long time, or TCP timeout is set very low)
c) By the application on the server

In either of those cases the server side SockJS impl will start a timeout (default 5 seconds). If the client does not reconnect with the same session id in that time, the session will be removed from the server

Yes, no, maybe, I don't know. Shall I repeat the question?




On 14/12/2012 19:51, Shripad K wrote:

Shripad K

unread,
Dec 14, 2012, 4:28:03 PM12/14/12
to Tim Fox, Marek Majkowski, SockJS
On Sat, Dec 15, 2012 at 2:34 AM, Tim Fox <timv...@gmail.com> wrote:
So, to summarise (here is my mini spec):

For streaming transports:

The connection can be closed either
a) Unilaterally by the client
b) Because of TCP timeout on the server
c) By the application on the server
d) By the Server SockJS implementation because > 128 KiB has been sent

In either of those cases the server side SockJS impl will start a timeout (default 5 seconds). If the client does not reconnect with the same session id in that time, the session will be removed from the server


Correct.
 
For polling transports:

The connection can be closed either
a) Unilaterally by the client (this is normal after each poll)
b) Because of TCP timeout on the server (unlikely but posssible if the poll takes a very long time, or TCP timeout is set very low)
c) By the application on the server

In either of those cases the server side SockJS impl will start a timeout (default 5 seconds). If the client does not reconnect with the same session id in that time, the session will be removed from the server


Correct.
 
Yes, no, maybe, I don't know. Shall I repeat the question?

Specific transport implementations may vary, but this is how it pretty much abstracts everything. :) 

Serge S. Koval

unread,
Dec 14, 2012, 4:54:47 PM12/14/12
to timv...@gmail.com, Shripad K, Marek Majkowski, SockJS
On Fri, Dec 14, 2012 at 11:04 PM, Tim Fox <timv...@gmail.com> wrote:
> For streaming transports:
> The connection can be closed either
> a) Unilaterally by the client
> b) Because of TCP timeout on the server
> c) By the application on the server
> d) By the Server SockJS implementation because > 128 KiB has been sent
>
> In either of those cases the server side SockJS impl will start a timeout
> (default 5 seconds).
No, that's not right. 'a' and 'b' are errorneous conditions and server
should close session immediately.
However, if 'c' and 'd' are valid conditions, as server is closing
connection. In this case, client should come for more data in 5s.

> For polling transports:
>
> The connection can be closed either
> a) Unilaterally by the client (this is normal after each poll)
> b) Because of TCP timeout on the server (unlikely but posssible if the poll
> takes a very long time, or TCP timeout is set very low)
> c) By the application on the server
Same as above. 'a' and 'b' should be treated as error and session
should be closed right away. Client should not close connection - it
is server responsibility to finish polling cycle and close connection.

To sum it up: as long as server is closing connection, everything is fine.

See here: http://sockjs.github.com/sockjs-protocol/sockjs-protocol-0.3.3.html#section-149

Serge.

Shripad K

unread,
Dec 14, 2012, 11:33:37 PM12/14/12
to Serge S. Koval, Tim Fox, Marek Majkowski, SockJS
Well he was talking about connection close, not about discarding session information :) If discarding session info, then yes you are correct. But socket connection is closed in all those cases immediately (except TCP timeout where the socket is closed once timeout expires... but still immediately on expiration).

Shripad K

unread,
Dec 14, 2012, 11:43:12 PM12/14/12
to Serge S. Koval, Tim Fox, Marek Majkowski, SockJS
On Sat, Dec 15, 2012 at 10:03 AM, Shripad K <assortme...@gmail.com> wrote:
On Sat, Dec 15, 2012 at 3:24 AM, Serge S. Koval <serge...@gmail.com> wrote:
On Fri, Dec 14, 2012 at 11:04 PM, Tim Fox <timv...@gmail.com> wrote:
> For streaming transports:
> The connection can be closed either
> a) Unilaterally by the client
> b) Because of TCP timeout on the server
> c) By the application on the server
> d) By the Server SockJS implementation because > 128 KiB has been sent
>
> In either of those cases the server side SockJS impl will start a timeout
> (default 5 seconds).
No, that's not right. 'a' and 'b' are errorneous conditions and server
should close session immediately.
However, if 'c' and 'd' are valid conditions, as server is closing
connection. In this case, client should come for more data in 5s.



There is no distinction in SockJS between erroneous and normal close. If you have tried it, you can see that even for streaming transports, the session is discarded after 5 seconds (in the case of 'a' and 'b') after the client goes away/TCP timeout. The close callback is not triggered immediately. Same is the case for polling.

On a side note to Marek:

Why are there two if's?

and

@recv.didClose() also calls @unregister() unless i'm missing something?

Tim Fox

unread,
Dec 15, 2012, 5:19:04 AM12/15/12
to Shripad K, Serge S. Koval, Marek Majkowski, SockJS
On 15/12/2012 04:43, Shripad K wrote:

On Sat, Dec 15, 2012 at 10:03 AM, Shripad K <assortme...@gmail.com> wrote:
On Sat, Dec 15, 2012 at 3:24 AM, Serge S. Koval <serge...@gmail.com> wrote:
On Fri, Dec 14, 2012 at 11:04 PM, Tim Fox <timv...@gmail.com> wrote:
> For streaming transports:
> The connection can be closed either
> a) Unilaterally by the client
> b) Because of TCP timeout on the server
> c) By the application on the server
> d) By the Server SockJS implementation because > 128 KiB has been sent
>
> In either of those cases the server side SockJS impl will start a timeout
> (default 5 seconds).
No, that's not right. 'a' and 'b' are errorneous conditions and server
should close session immediately.
However, if 'c' and 'd' are valid conditions, as server is closing
connection. In this case, client should come for more data in 5s.



There is no distinction in SockJS between erroneous and normal close. If you have tried it, you can see that even for streaming transports, the session is discarded after 5 seconds (in the case of 'a' and 'b') after the client goes away/TCP timeout. The close callback is not triggered immediately. Same is the case for polling.

As you can see, in the absence of a spec we just end up arguing over what the 'correct behaviour' should be. If someone wrote this down and it got the 'official' stamp of approval, then we'd able to say 'Consult the table in section 3.4.2 Connection close behaviour'.

Case closed.

Serge S. Koval

unread,
Dec 15, 2012, 6:24:30 AM12/15/12
to Shripad K, Tim Fox, Marek Majkowski, SockJS
Then it is a bug in sockjs-node implementation if sockjs-node does not
close session immediately on networking error or if close was not
initiated by the server itself. Which should not be the case, because
there's test just for that:
http://sockjs.github.com/sockjs-protocol/sockjs-protocol-0.3.3.html#section-149

Even though session will be kept for 5 seconds, it will be in "closed"
state, according to this comment:

Polling request now, after we aborted previous one, should trigger a
connection closure. Implementations may close the session and forget
the state related. Alternatively they may return a 1002 close message.

Serge.

Shripad K

unread,
Dec 15, 2012, 7:08:57 AM12/15/12
to Serge S. Koval, Tim Fox, Marek Majkowski, SockJS
It definitely does not close session immediately on networking error... at least not from what I can see in the source code. If i'm looking at the wrong place do tell me where i should be looking at (I have studied the source thoroughly and I can find the session discarding stuff only in src/transport.coffee).

@Tim: The spec exists but for reasons unknown, some parts of the spec are not implemented in the source (unless i'm looking at the wrong files which i doubt :) ). @Marek can explain this better.

As far as polling is concerned, I feel the timeout should be controlled by the server. Depending on the client is highly unreliable. For instance, jsonp GET requests cannot be aborted from the client end. (removing the script does not close the connection). So with jsonp-polling, lots of sockets end up in ESTABLISHED state (until that tab/window is closed).

Polling controlled at the server end also has its disadvantages... adding more timers increases the number of syscalls/more CPU usage.

Serge S. Koval

unread,
Dec 15, 2012, 7:15:53 AM12/15/12
to Shripad K, Tim Fox, Marek Majkowski, SockJS
I guess here it is -
https://github.com/sockjs/sockjs-node/blob/master/src/transport.coffee#L232

All transports are inherited from ResponseReceiver class and it is
sibling of the GenericReceiver.
Looks like there's problem in the test/sockjs-node, it expects 1002
status code, but it sockjs-node sends 1006.
That's not a problem, as session getting removed immediately anyway:
https://github.com/sockjs/sockjs-node/blob/master/src/transport.coffee#L251

Serge.

Shripad K

unread,
Dec 15, 2012, 7:24:52 AM12/15/12
to Serge S. Koval, Tim Fox, Marek Majkowski, SockJS
Yeah that code is the most confusing. It is a bug for sure!!!! Check this:

didAbort first does a didClose() which in-turn does an session.unregister() : https://github.com/sockjs/sockjs-node/blob/master/src/transport.coffee#L243

session.unregister() does the following:

1. NULLs the session (so obviously the session info is discarded here)
2. starts a timeout of 5 seconds: https://github.com/sockjs/sockjs-node/blob/master/src/transport.coffee#L143 which will call didTimeout() on expiry: https://github.com/sockjs/sockjs-node/blob/master/src/transport.coffee#L159 (and hence, like I said earlier, the disconnect callback is emitted after 5 seconds)

Then it does a weird thing. It checks again for "session" which will now but null (was nulled in step 1) : https://github.com/sockjs/sockjs-node/blob/master/src/transport.coffee#L244
So it will never call session.didTimeout() as that block will never be executed.

If my understanding is wrong, do tell me where & why :)

Shripad K

unread,
Dec 15, 2012, 7:33:33 AM12/15/12
to Serge S. Koval, Tim Fox, Marek Majkowski, SockJS
Also forget the source, just do a normal test by opening a iframe-htmlfile/eventsource connection and then using ipfw/iptables and block the port (emulating cable removal). Lower the TCP keepalive value to something sane (like 50 seconds). You can see that it closes the session at 55th second from opening the connection (5 second delay).

Tim Fox

unread,
Dec 15, 2012, 12:21:11 PM12/15/12
to Shripad K, Serge S. Koval, Marek Majkowski, SockJS
On 15/12/2012 12:08, Shripad K wrote:
It definitely does not close session immediately on networking error... at least not from what I can see in the source code. If i'm looking at the wrong place do tell me where i should be looking at (I have studied the source thoroughly and I can find the session discarding stuff only in src/transport.coffee).

@Tim: The spec exists

Where?

Shripad K

unread,
Dec 15, 2012, 1:28:16 PM12/15/12
to Tim Fox, Serge S. Koval, Marek Majkowski, SockJS
On Sat, Dec 15, 2012 at 10:51 PM, Tim Fox <timv...@gmail.com> wrote:
On 15/12/2012 12:08, Shripad K wrote:
It definitely does not close session immediately on networking error... at least not from what I can see in the source code. If i'm looking at the wrong place do tell me where i should be looking at (I have studied the source thoroughly and I can find the session discarding stuff only in src/transport.coffee).

@Tim: The spec exists

Where?


Shripad K

unread,
Dec 15, 2012, 1:35:58 PM12/15/12
to Tim Fox, Serge S. Koval, Marek Majkowski, SockJS
Also, @Majek, you can dump jsonp-polling and include iframe-htmlfile for even IE6/7. Any reason why you are not using iframe-htmlfile for IE6/7?

Tim Fox

unread,
Dec 15, 2012, 2:52:21 PM12/15/12
to Shripad K, Serge S. Koval, Marek Majkowski, SockJS
On 15/12/2012 18:28, Shripad K wrote:
On Sat, Dec 15, 2012 at 10:51 PM, Tim Fox <timv...@gmail.com> wrote:
On 15/12/2012 12:08, Shripad K wrote:
It definitely does not close session immediately on networking error... at least not from what I can see in the source code. If i'm looking at the wrong place do tell me where i should be looking at (I have studied the source thoroughly and I can find the session discarding stuff only in src/transport.coffee).

@Tim: The spec exists

Where?



Ah, that, ahem, "spec" ;)

Marek Majkowski

unread,
Dec 15, 2012, 4:30:04 PM12/15/12
to Tim Fox, Shripad K, Serge S. Koval, SockJS
Answers, in random order. This is a long thread, please ask again if I
missed something.

On Sat, Dec 15, 2012 at 4:43 AM, Shripad K <assortme...@gmail.com> wrote:
> There is no distinction in SockJS between erroneous and normal close.

Then it is a bug.

On Sat, Dec 15, 2012 at 4:43 AM, Shripad K <assortme...@gmail.com> wrote:
> On a side note to Marek:
>
> Why are there two if's?
>
> https://github.com/sockjs/sockjs-node/blob/master/src/transport.coffee#L203
> and
> https://github.com/sockjs/sockjs-node/blob/master/src/transport.coffee#L205
>
> @recv.didClose() also calls @unregister() unless i'm missing something?

Three in fact:

if @recv
# Go away. doSendFrame can trigger didClose which can
# trigger unregister. Make sure the @recv is not null.
@recv.doSendFrame(@close_frame)
if @recv
@recv.didClose()
if @recv
@unregister()

@recv.didClose() will call unregister a polling transports, so
@recv may be already NULL before @unregister() line.


On Sat, Dec 15, 2012 at 12:08 PM, Shripad K <assortme...@gmail.com> wrote:
> It definitely does not close session immediately on networking error...
>
On Sat, Dec 15, 2012 at 12:24 PM, Shripad K <assortme...@gmail.com> wrote:
> Yeah that code is the most confusing. It is a bug for sure!!!! Check this:
>
> didAbort first does a didClose() which in-turn does an session.unregister()
> :
> https://github.com/sockjs/sockjs-node/blob/master/src/transport.coffee#L243
>
> session.unregister() does the following:
>
> 1. NULLs the session (so obviously the session info is discarded here)
> 2. starts a timeout of 5 seconds:
> https://github.com/sockjs/sockjs-node/blob/master/src/transport.coffee#L143
> which will call didTimeout() on expiry:
> https://github.com/sockjs/sockjs-node/blob/master/src/transport.coffee#L159
> (and hence, like I said earlier, the disconnect callback is emitted after 5
> seconds)
>
> Then it does a weird thing. It checks again for "session" which will now but
> null (was nulled in step 1) :
> https://github.com/sockjs/sockjs-node/blob/master/src/transport.coffee#L244
> So it will never call session.didTimeout() as that block will never be
> executed.
>
> If my understanding is wrong, do tell me where & why :)

To repeat the code:

didAbort: (status, reason) ->
session = @session
@didClose(status, reason)
if session
session.didTimeout()

we:
1) copy @session to local variable ("@session" != "session")
2) nicely cleanup current receiver, and call didClose which
calls unregister and starts a timer
3) fake a timer timeout by calling "session.didTimeout()"

So didAbort() is equal to session being abandoned and
after a 5-second timeout.

On Sat, Dec 15, 2012 at 6:35 PM, Shripad K <assortme...@gmail.com> wrote:
> Also, @Majek, you can dump jsonp-polling and include iframe-htmlfile for
> even IE6/7. Any reason why you are not using iframe-htmlfile for IE6/7?

Iframe transports don't work on IE6 and IE7 (no window.postMessage API).

On Sat, Dec 15, 2012 at 7:52 PM, Tim Fox <timv...@gmail.com> wrote:
> Ah, that, ahem, "spec" ;)

Tim, you're doing it again. I'm not sure how writing documentation
will help your issues. If I can't help you by answering your questions
on the mailing list, how a quickly outdated document is going
to help???

Marek

Tim Fox

unread,
Dec 15, 2012, 5:02:17 PM12/15/12
to Marek Majkowski, Shripad K, Serge S. Koval, SockJS
Point is, you wouldn't have to keep answering my questions on the
mailing list if you wrote a document. I would be off your back - I'm
sure that's something you would appreciate ;)

It wouldn't even have to be a big document - SockJS is not that complex.


> how a quickly outdated document
Why would it get outdated?

Put it under version control in git. When you make a change that
requires a change in the document, change it. When you release a new
version, release a new version of the doc. Tag it like anything else.
It's not rocket science.

Marek Majkowski

unread,
Dec 15, 2012, 5:33:03 PM12/15/12
to timv...@gmail.com, SockJS
On Sat, Dec 15, 2012 at 10:02 PM, Tim Fox <timv...@gmail.com> wrote:
> Point is, you wouldn't have to keep answering my questions on the mailing
> list if you wrote a document. I would be off your back - I'm sure that's
> something you would appreciate ;)
>
> It wouldn't even have to be a big document - SockJS is not that complex.
>
>> how a quickly outdated document
>
> Why would it get outdated?
>
> Put it under version control in git. When you make a change that requires a
> change in the document, change it. When you release a new version, release a
> new version of the doc. Tag it like anything else. It's not rocket science.

Tim,

Answering technical questions fills me with joy. Especially if
I already know the answer! Please ask the same questions all over
again, and when I'm tired of them I'll add answers to sockjs-protocol.

Marek

Shripad K

unread,
Dec 15, 2012, 11:34:50 PM12/15/12
to Marek Majkowski, Tim Fox, Serge S. Koval, SockJS
Yes you are right @Marek. I forget that you are checking for session local variable, not @session. Sorry!
 

On Sat, Dec 15, 2012 at 6:35 PM, Shripad K <assortme...@gmail.com> wrote:
> Also, @Majek, you can dump jsonp-polling and include iframe-htmlfile for
> even IE6/7. Any reason why you are not using iframe-htmlfile for IE6/7?

Iframe transports don't work on IE6 and IE7 (no window.postMessage API).

I got it working in my implementation. Here is my implementation (it works cross domain too) :) :

// SCRIPT:

function unload() {
    transferDoc = null;
    try {
        CollectGarbage();
    } catch(e) {
        // do nothing
    }
}

if(!!window.attachEvent) {
    window.attachEvent("onbeforeunload", unload);
    window.attachEvent("onunload", unload);
} else {
    window.addEventListener("beforeunload", unload, false);
    window.addEventListener("unload", unload, false);
}

// For xdomain purpose
var _uri = [];
_uri.push(scheme+"://"); // scheme is http/https
_uri.push(document.domain);
transferDoc = new window["ActiveXObject"]("htmlfile");
transferDoc.open();
transferDoc.write(
    "<html><script>"+
    "document.domain='"+_uri.join("")+"';"+
    "</script></html>"
);
transferDoc.close();
var ifrdiv = transferDoc.createElement("div");
transferDoc.body.appendChild(ifrdiv);
ifrdiv.innerHTML = "<iframe src='" + ENDPOINT + "'></iframe>";

transferDoc.parentWindow["callback"] = onmessage_handler;

IFRAME:

<html><head></head><body><script>
var isIE = /msie/i.test(navigator.userAgent);
function sendMessage(m){
  if(isIE) {
     if(top.postMessage) {
        top.postMessage(m, "*");
     } else if(parent.callback) {
        parent.callback({data: m});
     }
  } else {
        if(top.postMessage) {
             top.postMessage(m, "*");
        }
  }
}</script></body></html>

Marek Majkowski

unread,
Dec 16, 2012, 6:04:09 AM12/16/12
to Shripad K, SockJS
On Sun, Dec 16, 2012 at 4:34 AM, Shripad K <assortme...@gmail.com> wrote:
> "document.domain='"+_uri.join("")+"';"+

So you're saying that you can set "document.domain" of the iframe to
_any_ domain.
That doesn't sound right. AFAIK you can only set document.domain to a subdomain
of the original domain (for example: "blah.com" or maybe even "com" if
page is from
"www.blah.com")

Reference:
http://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_DOM_access

"""
Any page may set document.domain parameter to a right-hand,
fully-qualified fragment of its current host name (e.g.,
foo.bar.example.com may set it to example.com, but not ample.com). If
two pages explicitly and mutually set their respective document.domain
parameters to the same value, and the remaining same-origin checks are
satisfied, access is granted.
"""

Shripad K

unread,
Dec 16, 2012, 7:36:55 AM12/16/12
to Marek Majkowski, SockJS
You can set document.domain to any domain only in IE6/7. It was fixed in IE8. There was no notion of Same origin policy for IE6/7 as far as document.domain is concerned :) So yes, this works and it works cross domain.

Shripad K

unread,
Dec 16, 2012, 7:40:57 AM12/16/12
to Marek Majkowski, SockJS
Also, it only works if you create a htmlfile object.. not with an iframe. So if you are trying with only an iframe then it won't work. If you see my example, i'm creating the iframe within the htmlfile object (the htmlfile object is pointing to a different domain).

Shripad K

unread,
Dec 16, 2012, 7:45:21 AM12/16/12
to Marek Majkowski, SockJS
Also another point to note: If you do just: document.domain = document.domain the same origin policy applies. Prefixing the scheme bypasses same origin policy.

Shripad K

unread,
Dec 16, 2012, 7:48:07 AM12/16/12
to Marek Majkowski, SockJS
Discovered this beauty obscured in comments in this 2007 blog post : http://cometdaily.com/2007/11/18/ie-activexhtmlfile-transport-part-ii/#comment-5910
Reply all
Reply to author
Forward
0 new messages