1

Using ServiceStack’s Server Events feature I can sync two browsers if there are no cross-origin HTTP requests involved. It works as simple as documented:

(1) Plugins.Add(new ServerEventsFeature());

(2) A SyncRequest endpoint:

    [Route("/channels/{Channel}/sync", "POST")]
    public class SyncRequest : IReturnVoid
    {
        public string From { get; set; }
        public string ToUserId { get; set; }
        public string Channel { get; set; }
        public string Message { get; set; }
        public string Selector { get; set; }
    }
    public class SyncService : Service
    {
        public IServerEvents ServerEvents { get; set; }

        public void Any(SyncRequest request)
        {
            ServerEvents.NotifyChannel(request.Channel, "sync", request.From);
        }
    }

(3) In browser:

    var mychannel = 'example';
    var source= new EventSource(`${serviceUrl}/event-stream?channel={mychannel}`);
    source.onmessage = (m) => {}; // etc.

With this I can sync the browsers by calling the SyncRequest endpoint (in one browser) and processing the message that comes out of the EventSource in the other browser.

However, if the sync server is on another domain and cross-origin HTTP requests are needed, it fails. Plugins.Add(new CorsFeature(...)) appears to work after a while, but in Chrome (on Linux) I first see ERR_INVALID_CHUNKED_ENCODING errors in the console.

On the internet I see claims that Chrome is strict w.r.t. chunked encoding and that this may cause these ERR_INVALID_CHUNKED_ENCODING errors. I also see that the response to the /event-stream call has a Transfer-Encoding:chunked header but I don't know if this is indeed the cause and if so how to get rid of it.

In another question on ServiceStack's SSE plus CORS mythz suggests that response headers can be changed like so:

    Plugins.Add(new ServerEventsFeature {
        OnInit = request => {
            request.Response.AddHeader("Transfer-Encoding", "identity");
        },
        OnHeartbeatInit = request => {
            request.Response.AddHeader("Transfer-Encoding", "identity");
        }
    });

but this has no effect on the /event-stream?channel=example call - its Response Headers include Transfer-Encoding:chunked (and the heartbeat has Transfer-Encoding:identity by default).

Now the browser keeps trying to re-establish the connection using /event-stream?channel=example and the first time it succeeds we are good - the EventSource objects work, the heartbeats happen, and syncing is possible.

I am using ServiceStack/4.512 NET45 Unix/Mono.

So the question is: Is there a way to immediately establish an SSE connection without the ERR_INVALID_CHUNKED_ENCODING errors? Maybe ServiceStack has the common error referred to in another question?

1 Answers1

1

Chunked Transfer-Encoding is normal for Server Sent Events's long-running HTTP Response where the length is not known. The issue is likely due in Mono's HTTP implementation, if you're running on Linux/OSX it's recommended to run ServiceStack on .NET Core instead which is the supported option.

mythz
  • 141,670
  • 29
  • 246
  • 390
  • A new browser that tunes in to the channel triggers a message on the channel that may be incorrectly chunked, disrupting other browsers tuned in. In case of several browsers tuned in to the same channel I can see them struggling to get back on their feet, potentially disrupting others, not able to send/receive a sync request. There is hope, though, because the sync POST request, which calls NotifyChannel, works flawlessly all of the time. So somehow NotifyChannel manages to send a properly chunked message, whereas onConnect does not. Surely there must be a way to fix this! – Alex Zubrinsky Nov 25 '17 at 18:49
  • @AlexZubrinsky Transfer-Encoding responses are not generated by the framework, it's implicitly added by the underlying Web platform when it's not able to determine the Request length. The solution is if you're using Mono to migrate to .NET Core. Mono's ASP.NET implementation is buggy with no-one left supporting it. – mythz Nov 25 '17 at 18:53
  • Thank you! We'll sure end up on .NET Core some time. – Alex Zubrinsky Nov 25 '17 at 20:21