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

Start HttpServer in runZoned() causing uncaught error if the client closes the connection #17468

Closed
DartBot opened this issue Mar 13, 2014 · 19 comments
Assignees

Comments

@DartBot
Copy link

DartBot commented Mar 13, 2014

This issue was originally filed by @tomyeh


What steps will reproduce the problem?

  1. Run the test code appended at the end
  2. Visit localhost:8080
  3. Close the browser within 10 second
  4. The server terminated unexpected with the message shown below (after 10 second).

Notice that both runZoned() and response.write() must be used. Otherwise, no error message will be shown (except "Simulate a long operation"). However, it is still wrong -- response.done.catchError() shall be able to catch the error (see Issue #5)

Dart VM version: 1.2.0 (Tue Feb 25 06:18:15 2014) on "windows_ia32"

Console log:


Simulate a long operation
Uncaught Error: SocketException: Write failed, address = 127.0.0.1, port = 8080
Unhandled exception:
SocketException: Write failed, address = 127.0.0.1, port = 8080

­0 _rootHandleUncaughtError.<anonymous closure>.<anonymous closure> (dart:async/zone.dart:700)

­1 _asyncRunCallbackLoop (dart:async/schedule_microtask.dart:23)

­2 _asyncRunCallback (dart:async/schedule_microtask.dart:32)

­3 _asyncRunCallback (dart:async/schedule_microtask.dart:36)

­4 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:119)

Test Code:


import "dart:async";
import "dart:io";

import "dart:async";
import "dart:io";

void main() {
  HttpServer.bind("127.0.0.1", 8080).then((server) {
    runZoned(() {
    server.listen((request) {
      final response = request.response;
      response.done.catchError((err, stackTrace) {
        print("Closing a connection by client shall reach here");
      });

        response.write("write something to cause the exception");

      new Future.delayed(const Duration(seconds: 10), () {
        print("Simulate a long operation");
        response.close();
      });
    });
    }, onError: (err, stackTrace) {
      print("Uncaught: $err\n$stackTrace");
    });
  });
}

@kevmoo
Copy link
Member

kevmoo commented Mar 14, 2014

cc @Skabet.
cc @sgjesse.
Added Area-IO, Triaged labels.

@andersjohnsen
Copy link

Hi,

This code appears to be working with bleeding-edge. However, I'm not 100% sure if this is due to a actual fix, or changes that made this test not hit it anymore.

Keep open for now, for further investigations.

  • Anders

@DartBot
Copy link
Author

DartBot commented Mar 14, 2014

This comment was originally written by @tomyeh


Confirmed it doesn't throw the exception (r33495).

However, neither the catchError of response.done nor onError catch the socket exception either. In one of the old versions (I don't recall), done is the right place to catch this kind of abnormal connection termination. Or, in the current spec, it is ignored silently?

@andersjohnsen
Copy link

It's ignored silently. :)

@DartBot
Copy link
Author

DartBot commented Mar 14, 2014

This comment was originally written by @tomyeh


Then, how about if the user closed the browser before completing a long download? Will the server keep reading and sending if without this exception?

@andersjohnsen
Copy link

Depends:

  • using response.write(...) will simply ignore the data.
  • using response.addStream(...) will listen and immediately cancel the stream. If it was e.g. a file stream, that would propagate back and close the file for further reading.

@DartBot
Copy link
Author

DartBot commented Mar 14, 2014

This comment was originally written by @tomyeh


Got it. Thanks.

@andersjohnsen
Copy link

I'm closing this for now, as I'm unable to reproduce this. Please file a new one or open this one again, if you're able to somehow reproduce!

Thanks!

@DartBot
Copy link
Author

DartBot commented Apr 13, 2014

This comment was originally written by @tomyeh


Unfortunately, one of users reports a server crash with Dart 1.3 at http://stackoverflow.com/questions/22977471/rikulo-stream-crashes-daily-with-socketexception-os-error-broken-pipe-errno

As he reported, here is stacktrace after upgrading to Dart 1.3

Uncaught Error: SocketException: OS Error: Connection reset by peer, errno = 104, address = 0.0.0.0, port = 80
Unhandled exception:
SocketException: OS Error: Connection reset by peer, errno = 104, address = 0.0.0.0, port = 80
#­0 _rootHandleUncaughtError.<anonymous closure>.<anonymous closure> (dart:async/zone.dart:713)
#­1 _asyncRunCallbackLoop (dart:async/schedule_microtask.dart:23)
#­2 _asyncRunCallback (dart:async/schedule_microtask.dart:32)
#­3 _asyncRunCallback (dart:async/schedule_microtask.dart:36)
#­4 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:119)
Serge

@DartBot
Copy link
Author

DartBot commented Apr 15, 2014

This comment was originally written by @tomyeh


One of our engineers leaves the server running idly overnight (no request at all during this period). On the second day, Dart VM was dead with the following stack trace:

Uncaught Error: SocketException: Write failed, address = 0.0.0.0, port = 8081
Unhandled exception:
SocketException: Write failed, address = 0.0.0.0, port = 8081
#­0 _rootHandleUncaughtError.<anonymous closure>.<anonymous closure> (dart:async/zone.dart:713)
#­1 _AsyncCallbackEntry.callback (dart"async/schedule_microtask.dart:1)
#­2 _asyncRunCallbackLoop (dart:async/schedule_microtask.dart:23)
#­3 _asyncRunCallback (dart:async/schedule_microtask.dart:32)
#­4 _asyncRunCallback (dart:async/schedule_microtask.dart:36)
#­5 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:119)

@andersjohnsen
Copy link

Fixed in r35071. Thanks for linking to the SO thread, helped me identify the issue.


Added Fixed label.

@DartBot
Copy link
Author

DartBot commented Apr 16, 2014

This comment was originally written by ses...@gmail.com


Do you schedule a Dart 1.3.1 release with this patch ?

@andersjohnsen
Copy link

A 1.3 release is scheduled with this fix.

@kasperl
Copy link

kasperl commented Apr 23, 2014

A release with the fix has been sent out on the dev channel today (1.4.0-dev.3.0). It would be great if you could give us feedback on whether or not the issue has been resolved in that release -- so that we know if back porting the fix to the stable channel (1.3.x) is going to help.

@DartBot
Copy link
Author

DartBot commented Apr 24, 2014

This comment was originally written by sestegr...@gmail.com


I just upgraded to the latest Dart VM release from dev channel (1.4.0-dev.3.0).
It seems fixed now, I can't reproduce the issue after few hours, before the upgrade, it appeared in 10 seconds.

@kasperl
Copy link

kasperl commented May 1, 2014

The fix has been shipped to the stable channel as part of version 1.3.6.

@DartBot
Copy link
Author

DartBot commented May 4, 2014

This comment was originally written by ses...@gmail.com


I installed Dart VM 1.3.6 on my 4 servers.
The issue is still present, but the occurrence is very low : the issue occurred only 1 time on my slowest server.

Unhandled exception:
SocketException: OS Error: Broken pipe, errno = 32, address = 127.0.0.1, port = 49111
#­0 _rootHandleUncaughtError.<anonymous closure>.<anonymous closure> (dart:async/zone.dart:713)
#­1 _asyncRunCallbackLoop (dart:async/schedule_microtask.dart:23)
#­2 _asyncRunCallback (dart:async/schedule_microtask.dart:32)
#­3 _asyncRunCallback (dart:async/schedule_microtask.dart:36)
#­4 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:119)

@andersjohnsen
Copy link

Hi sestegra,

Would it be possible for you to attach or email me a code snippet, that produces this error?

Your program, is it only using HTTP, or is it also using WebSockets, etc?

Having something more concrete will make it a lot faster for me, to find a fix for this issue!

Thanks,

  • Anders

@andersjohnsen
Copy link

I looked into this some more, and have two more comments:

  1. It's possible to set up zones in a bad pattern, where the expected error-propagation is broken and errors end up being uncaught. This is not a bug in dart:io, but the specified behavior of zones.

  2. Breaking the error-propagation as mentioned in 1), I was only able to break with HttpExceptions, not SocketExceptions. Can you comment on the setup, as it may be something I haven't though of?

Thanks,

  • Anders

This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants