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

Surface websocket protocol errors to user applications #804

Closed

Conversation

smerritt
Copy link
Contributor

@smerritt smerritt commented Jun 22, 2023

Currently, if a websocket client sends bad data[1] to an application, the application just receives a generic error message with no indication of what went wrong. Also, the client just gets an aborted[2] websocket connection without any clue as to what they did wrong.

This commit changes two things: first, the application now gets an error event describing what was wrong with the received data. This gives the application's owner some clue what's going wrong.

Second, we now send a Close frame to the client with an appropriate error code, as we SHOULD do[3]. In an ideal world, this will let the client's owner figure out what they're doing wrong and fix it.

[1] Invalid according to RFC 6455, for example sending a continuation frame without a preceding start frame or sending a frame with reserved bits (RSV1, RSV2, and RSV3; see
https://datatracker.ietf.org/doc/html/rfc6455#section-5.2) set.

[2] The underlying TCP connection is closed without first sending a websocket "Close" frame.

[3] https://datatracker.ietf.org/doc/html/rfc6455#section-7.1.7

@github-actions
Copy link

github-actions bot commented Jun 22, 2023

CLA Assistant Lite bot All contributors have signed the CLA ✍️ ✅

@smerritt smerritt force-pushed the smerritt/websocket-protocol-errors branch from 8c33a48 to 6ff569a Compare June 22, 2023 23:05
@smerritt
Copy link
Contributor Author

I have read the CLA Document and I hereby sign the CLA

github-actions bot added a commit that referenced this pull request Jun 28, 2023
@smerritt smerritt force-pushed the smerritt/websocket-protocol-errors branch from 26e1402 to 013463a Compare July 10, 2023 23:03
@smerritt smerritt changed the title WIP: surface websocket protocol errors to user applications Surface websocket protocol errors to user applications Jul 10, 2023
@smerritt smerritt marked this pull request as ready for review July 10, 2023 23:05
@smerritt smerritt force-pushed the smerritt/websocket-protocol-errors branch from 013463a to df9776c Compare July 11, 2023 21:57
@smerritt smerritt force-pushed the smerritt/websocket-protocol-errors branch from dc82b35 to c929b98 Compare July 14, 2023 21:30
jasnell
jasnell previously approved these changes Jul 16, 2023
@smerritt smerritt force-pushed the smerritt/websocket-protocol-errors branch from c929b98 to a9cf330 Compare July 19, 2023 20:13
src/workerd/api/web-socket.h Outdated Show resolved Hide resolved
src/workerd/api/web-socket.c++ Show resolved Hide resolved
src/workerd/api/web-socket.c++ Outdated Show resolved Hide resolved
auto upstream = other->pumpTo(*self);
auto downstream = self->pumpTo(*other);
auto upstream = other->pumpTo(*self).catch_([](kj::Exception&& e) {
KJ_UNWRAP_OR(WebSocketProtocolError::fromException(e), {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be misreading this, but I suspect:

if (WebSocketProtocolError::fromException(e) == nullptr) {
    throw e;
}

may have clearer intent. KJ_UNWRAP_OR returns the inner value on success, but we don't seem to be doing anything with that value here so I'm wondering if something was supposed to be done with it?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm actually not sure if it matters all that since this is pretty much passing through the error, but you might also want to use kj::throwFatalException(e) instead. I believe that it basically extends our async stack a bit?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

btw, can this be written to use coroutine syntax rather than using catch_?

And yes, this should use kj::throwFatalException(e) instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, that's how you say "this Maybe is empty". I'd found KJ_IF_MAYBE(_, m){} else { ... }, but that's ugly.

(In my ideal world, kj::Maybe would provide operator bool() for "has stuff in it", or maybe a .empty() method, but this is not that world.)

I fixed everything but the coroutine syntax. I can convert each individual pumpTo call, but currently the two promises get joined down below and I'm not sure what to do with that. Suggestions welcome.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jasnell I've coroutine-ified things as much as I can. There's still a call to kj::joinPromises that I don't see how to get rid of, but there's no more catch_. Does this look good to you?

src/workerd/api/web-socket.c++ Outdated Show resolved Hide resolved
@jasnell jasnell dismissed their stale review July 21, 2023 20:59

Needs updating and rebasing

@smerritt smerritt force-pushed the smerritt/websocket-protocol-errors branch 3 times, most recently from 4445478 to 155b33b Compare July 26, 2023 02:05
MellowYarker
MellowYarker previously approved these changes Jul 26, 2023
Copy link
Contributor

@MellowYarker MellowYarker left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Sam!

@smerritt smerritt force-pushed the smerritt/websocket-protocol-errors branch from 155b33b to d35d1f1 Compare July 26, 2023 23:36
@smerritt smerritt force-pushed the smerritt/websocket-protocol-errors branch 2 times, most recently from 920f4ee to eb52246 Compare July 28, 2023 18:57
@MellowYarker
Copy link
Contributor

🙃 it just occurred to me that the hibernatable websocket readloop is outside the regular Workerd web-socket code. Could you also update workerd/io/hibernation-manager.c++'s readLoop so we surface the error there too?

@MellowYarker MellowYarker dismissed their stale review July 31, 2023 14:03

Needs updates for hibernation

@smerritt smerritt force-pushed the smerritt/websocket-protocol-errors branch from eb52246 to 32c00d4 Compare August 3, 2023 18:44
Currently, if a websocket client sends bad data[1] to an application, the
application just receives a generic error message with no indication
of what went wrong. Also, the client just gets an aborted[2] websocket
connection without any clue as to what they did wrong.

This commit changes two things: first, the application now gets an
error event describing what was wrong with the received data. This
gives the application's owner some clue what's going wrong.

Second, we now send a Close frame to the client with an appropriate
error code, as we SHOULD do[3]. In an ideal world, this will let the
client's owner figure out what they're doing wrong and fix it.

[1] Invalid according to RFC 6455, for example sending a continuation
frame without a preceding start frame or sending a frame with reserved
bits (RSV1, RSV2, and RSV3; see
https://datatracker.ietf.org/doc/html/rfc6455#section-5.2) set.

[2] The underlying TCP connection is closed without first sending a
websocket "Close" frame.

[3] https://datatracker.ietf.org/doc/html/rfc6455#section-7.1.7
@smerritt smerritt force-pushed the smerritt/websocket-protocol-errors branch from 32c00d4 to 29c39b0 Compare November 28, 2023 20:48
@smerritt smerritt requested review from a team as code owners November 28, 2023 20:48
@smerritt smerritt marked this pull request as draft November 28, 2023 20:57
@smerritt
Copy link
Contributor Author

I'm dusting this change off after months of ignoring it. It still needs to include hibernating websockets, so I've marked as draft for the time being.

@smerritt
Copy link
Contributor Author

Obsoleted by capnproto/capnproto#1896, which handles the error much closer to its cause

@smerritt smerritt closed this Jan 29, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants