Proxy feature doesn't work fully with server sent events

The new proxy feature is working great (apart from the content length issue that has been fixed in the current pre release version)

I have setup proxies using this new feature for my server sent events, /event-stream proxies absolutely fine, however when I do the same for /event-heartbeat I get a “411 length required” http error on the request?

It’s something to do with content length and chunked transfer encoding. When I use my own custom proxy feature in a raw http handler it works fine.

Thanks for any help.

We definitely don’t recommend using the App-level ProxyFeature for a long-running HTTP Stream like SSE which keeps both the HTTP Worker Request Thread open as well as the .NET HttpWebRequest with the underlying event stream which are susceptible to timeout and execution exceptions.

With that said I added an Integration test to debug what happens when trying to connect to a ServerEvent over the Proxy:

Proxy Registration to Chat SSE Server:

Plugins.Add(new ProxyFeature(
    matchingRequests: req => req.PathInfo.StartsWith("/chat"),
    resolveUrl: req => "http://chat.servicestack.net" + req.RawUrl.Replace("/chat", "/"))
);

Connect with ServerEventsClient over proxy, rewriting HeartbeatUrl to go through proxy:

ServerEventsClient client = null;
var proxyBaseUrl = ListeningOn.CombineWith("chat");
client = new ServerEventsClient(proxyBaseUrl)
{
    OnConnect = async c =>
    {
        var proxyUrl = ListeningOn + c.HeartbeatUrl.Replace("http://chat.servicestack.net", "chat");
        client.ConnectionInfo.HeartbeatIntervalMs = 1000;
        client.ConnectionInfo.HeartbeatUrl = proxyUrl;
        var response = await proxyUrl.GetStringFromUrlAsync();
        Assert.That(response, Is.Empty);
    },
    OnHeartbeat = () =>
    {
        "Received Heartbeat".Print();
    },
    OnException = ex =>
    {
        ex.Message.Print();
    }
};

client.Start();
await client.Connect();

The behavior I did notice was:

  1. The client was able to connect to /event-stream over proxy where it was able to receive the onCommand message sent when a new /event-stream connection is established
  2. The Heartbeat is configured before OnConnect is called, so changes to ConnectionInfo only happens after the first heartbeat.
  3. After the first heartbeat, multiple heartbeats are all successfully sent through the proxy (200 Response) but the problem is that no notifications are sent over the /event-stream despite maintaining an open connection
  4. Eventually since no heartbeat is received from the Server the ServerEventsClient throws a TimeoutException and reconnects to the /event-stream
  5. After the reconnection, everything seems to work, the heartbeats are sent and the notifications are received from the server.

So I couldn’t repro any 411 HTTP Error Responses that you’re seeing, but either way connecting to Server Events over an SSE is going to be unreliable as we only have high-level HTTP-level access that’s exposed by .NET’s HttpWebRequest and no real control over the underlying HTTP connection which a proper Proxy like HA Proxy or nginx will have access to, which I’d recommend using over the App-level ProxyFeature.

That’s a shame. So there’s no real way to proxy the server sent events without using external software?

Another method I thought about was to use the .NET SSE client and make a connection from the proxy server to the backend SSE and then pass out the messages it receives over that connection to any clients that are connected to the proxy.

No idea on the performance of doing it this way.