Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EmbedIO HttpListenerMode doesn't detect client disconnects #457

Open
ketodiet opened this issue Feb 18, 2020 · 8 comments
Open

EmbedIO HttpListenerMode doesn't detect client disconnects #457

ketodiet opened this issue Feb 18, 2020 · 8 comments
Labels
area:http Issue with HttpListener and related types bug pinned Pinned issues are not closed automatically when stale. v3.x
Milestone

Comments

@ketodiet
Copy link

A quick overview:
A number of client apps connect via a rev proxy to a service. The rev proxy is an ASP.NET app and the service is a c# windows service using EmbedIO to handle incoming requests. Client apps have two connections each: one for pushing updates and the one polling for changes.
The issue described here is related to the polling.

The Bug:
When using Microsoft HttpListenerMode when a client disconnects & the rev proxy removes the connection in response, the next write on the poll connection will fail (i.e. the service will fail to send any updates or heartbeat to the client via the rev proxy).

When using EmbedIO HttpListenerMode in the exact same scenario, the service writes keep succeeding with no errors reported at all. Even if the rev proxy process is terminated (i.e. stopping the IIS server hosting the rev proxy) the writes keep working with no exceptions thrown.

That feels like a bug to me.

@rdeago rdeago added area:http Issue with HttpListener and related types bug v3.x labels Feb 18, 2020
@rdeago
Copy link
Collaborator

rdeago commented Feb 18, 2020

Hello @ketodiet, thanks for using EmbedIO!

The behavior you describe feels like a bug to me too.

Which type of module do you use for the polling? Looks like WebSocketModule from what you write, but I'd like to be sure.

@ketodiet
Copy link
Author

ketodiet commented Feb 18, 2020

Hi Riccardo, I'm not using websockets. The WebServer setup is:

_PublicAPI = new WebServer(o => o .WithUrlPrefix($"http://*:{port}/") .WithMode(HttpListenerMode.Microsoft) .WithSupportCompressedRequests(true)) .WithModule(new ActionModule(ctx => APIs.PublicAPI.Handle(ctx)));

Changing .WithMode from HttpListenerMode.Microsoft to HttpListenerMode.EmbedIO changes the behaviour as described in the bug.

In the case of HttpListenerMode.Microsoft I always get an System.Net.HttpListenerException exception when attempting to write on a closed connection.

@stale stale bot added the wontfix label Apr 18, 2020
@rdeago rdeago removed the wontfix label Apr 23, 2020
@unosquare unosquare deleted a comment from stale bot Apr 23, 2020
@rdeago rdeago added this to the 4.0.0 milestone Apr 23, 2020
@rdeago
Copy link
Collaborator

rdeago commented Apr 23, 2020

Hi @ketodiet, sorry for the delay. From what I could see from the source code, there are actually some flaws in connection management. I've begun an almost complete refactor of that part of EmbedIO, but in doing so I had to introduce a handful of breaking changes, so I'm afraid you'll have to wait for version 4 to see this issue (hopefully) fixed.

@rdeago rdeago added the pinned Pinned issues are not closed automatically when stale. label Apr 23, 2020
@simontuffley
Copy link

Hi Riccardo,

We're experiencing the exact same issue. Do you have any idea when we may see v4?

@radioegor146
Copy link
Contributor

@ketodiet, @simontuffley can you give me an example of code for continuous writes on HTTP connection?

@OffTimers
Copy link

OffTimers commented Nov 18, 2021

I confirm that there is such disconnection behavior. the code to repeat the error is simple:

[Route(HttpVerbs.Get, "/test")]
    public async Task Test()
    {
        try {
            byte[] dataBuffer = new byte[512];
            using (var stream = HttpContext.OpenResponseStream()) {
                while (true) {
                     await stream.WriteAsync(dataBuffer, 0, dataBuffer.Length);
                     await Task.Delay(1000);
                }
            }
        } catch (Exception e) { Debug.WriteLine($"{e}"); }
    }

It is convenient to receive data using curl command line, as well as terminate connections using ctl-c.

At the same time, in the debugger during debugging, the occurring exceptions associated with the advice are visible, but they are not returned as exceptions to the code of the method from which it was called.

@OffTimers
Copy link

OffTimers commented Nov 19, 2021

Small changes in the source codes of the library easily solve this problem.
The file /src/packages/EmbedIO/Net/Internal/ResponseStream needs to be modified:

remove:
internal class ResponseStream : Stream
insert:
public class ResponseStream : Stream

remove:
private readonly bool _ignoreErrors;

insert and rename all _ignoreErrors to IgnoreErrors
public bool IgnoreErrors { get; set; } = true;

next:

[Route(HttpVerbs.Get, "/test")]
    public async Task Test()
    {
        try {
            byte[] dataBuffer = new byte[512];
            using (var stream = HttpContext.OpenResponseStream()) {
                if (stream is EmbedIO.Net.Internal.ResponseStream s)
                    s.IgnoreErrors = false;
                while (true) {
                     await stream.WriteAsync(dataBuffer, 0, dataBuffer.Length);
                     await Task.Delay(1000);
                }
            }
        } catch (Exception e) { Debug.WriteLine($"{e}"); }
    }

@klasyc
Copy link

klasyc commented Jan 5, 2023

Another solution to this issue is globally enabling the write errors by configuring the WebServer's Listener object:

server.Listener.IgnoreWriteExceptions = false;
await server.RunAsync();

This method does not require touching the library internal class.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area:http Issue with HttpListener and related types bug pinned Pinned issues are not closed automatically when stale. v3.x
Projects
None yet
Development

No branches or pull requests

6 participants