3

I have a websocket server where I call websocket::stream::async_accept to perform a handshake with the client.

I also set a decorator to modify the headers like this

conn->get_websocket_stream().set_option(boost::beast::websocket::stream_base::decorator(
[this, self, conn](boost::beast::websocket::response_type& response)
{
    // modify response
    
    if (some_condition)
    {
        conn->close(); // is it OK?
    }
});

conn->get_websocket_stream().async_accept(request, ...);

Inside the decorator, if a given condition is met, I need to abort the execution of async_accept by closing the connection to the client.

Is it allowed to close the connection to the client inside the decorator? I didn't find an answer to this question in the documentation https://www.boost.org/doc/libs/1_81_0/libs/beast/doc/html/beast/using_websocket/decorator.html

UPDATE conn is a connection object, a normal asio session based on shared_ptr.

get_websocket_stream() returns websocket::stream

conn->close() simply closes the socket (socket used by websocket::stream)

3
  • Please show the relevant code. We don't know what conn is or what conn->close() ends up doing with anything we can reason about. I suspect you're going to say get_websocket_stream() gives a beast::websocket::stream<>& and close() calls close() on that stream. That's would obviously NOT be valid for two reasons: 1. close() isn't valid until the ws handshake completes and 2. close() constitutes a write, and the handshake constitutes writes. You cannot overlap the writes. Instead cancel operations, the lower layer and/or raise an exception Commented Aug 8 at 12:50
  • Oh, and it's also not ok to mix async and sync operations on beast::websocket::stream<> Commented Aug 8 at 12:51
  • @sehe "I suspect you're going to say get_websocket_stream() gives a beast::websocket::stream<>&": yes, "and close() calls close() on that stream.": No, close just closes socket used by websocket::stream Commented Aug 8 at 12:57

1 Answer 1

5

Decorators lack a way to report error. Raising exceptions will break the flow, but will likely cause more side-effects than just invalidating the current session. Probably the best you can do is replacing the entire response with an appropriate kind of HTTP error code:

// decorate upgrade response
ws.set_option(boost::beast::websocket::stream_base::decorator(
    [](boost::beast::http::response<boost::beast::http::string_body>& res) {
        res.result(boost::beast::http::status::i_am_a_teapot);
        res.reason("The proxy doesn't like your request");
    }));

You may be tempted to just overwrite the entire request:

    res = {boost::beast::http::status::i_am_a_teapot, 11/*, "Some body text"*/};

Sadly, this is against the documented contract, which specifically warns of UB:

Undefined behavior results if the decorator modifies the fields specific to perform the WebSocket Upgrade, such as the Upgrade or Connection fields.

Side Notes

I'm a little confused. If conn is "a normal Asio session based on shared_ptr" why on earth is async_accept being triggered outside that "normal session" violating LoD in the process.

Sign up to request clarification or add additional context in comments.

9 Comments

Thank you so much! I understood your proposed solution, it looks interesting. However, I did not understand whether it is allowed to close the socket in the decorator immediately or not?
Also, if I touch websocket-specific headers (for example, remove this headers) I think UB is came according to documentation: "Undefined behavior results if the decorator modifies the fields specific to perform the WebSocket Upgrade, such as the Upgrade or Connection fields." boost.org/doc/libs/1_81_0/libs/beast/doc/html/beast/…
Closing the underlying socket should probably be fine (assuming thread safety) but not the best idea. I'd probably cancel operations instead.
Regarding the documented UB: that's a very good note. I happen to think the documentation is currently overly restrictive, but I could be wrong. Also, Beast clearly reserves the right to depend on these headers to stay valid and unchanged, so that's that. I'll amend the answer text.
I got you, thank you so much!
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.