-
Notifications
You must be signed in to change notification settings - Fork 26
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
Making Soketto easier to use with http
types (and hyper
)
#48
Conversation
…to with http types
@@ -40,7 +40,7 @@ jobs: | |||
uses: actions-rs/cargo@v1.0.3 | |||
with: | |||
command: check | |||
args: --all-targets | |||
args: --all-targets --all-features |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now that we have a feature, make sure CI checks the code behind it
|
||
[[example]] | ||
name = "hyper_server" | ||
required-features = ["http"] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This just makes the error messages nicer when trying to run the example.
I'd definitely appreciate some feedback on the API design here (and whether we want it at all)! Part of me likes the idea of making it easier to use Soketto with the common |
src/handshake/http.rs
Outdated
/// This is handed back on a successful call to [`upgrade_request`]. | ||
pub struct Upgraded { | ||
/// This should be handed back to the client to complete the upgrade. | ||
pub response: http::Response<()>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We are actually only returning a set of headers, so I could conceivably return just those, and let the caller construct a Response
themselves. Headers would be a more precise type, but also add a little more overhead to using (I expect people should just return this as-is pretty much)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is useful; it's likely a common usage scenario and I think it's good to have a nice example for it. Left a few questions and suggestions.
src/handshake/server.rs
Outdated
@@ -126,6 +132,16 @@ impl<'a, T: AsyncRead + AsyncWrite + Unpin> Server<'a, T> { | |||
self.socket | |||
} | |||
|
|||
/// Configure the server based on the [`ServerConfiguration`] payload provided. This |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should be explicit about that it is the extensions that can be configured this way, and perhaps even mention that the deflate extension is the only one available?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My initial aim here was to have a fairly opaque object that may just be used for extensions or may be handy for other bits (because I wasn't sure whether we might want it to handle more), but I've been reading more about extensions, and have realised that:
- I think being more specific here does make sense; it's all about Extension configuration and I don't think anything else will come into play!
- I missed a piece of the puzzle! I realise (and it makes a lot of sense) that the server needs to respond with infomration on which extensions are agreed on, based in its configuration and the requested extensions, and that's a little awkward given the way things are currently split, so I'll need to think about that a little!
I actually ended up significantly reworking the code, because it turned out that my handling of extensions wasn't good enough! Now, there is a The API is different where necessary so that it's possible to actually do the relevant dance (because the thing returned from |
http::Request
types (and hyper
)http
types (and hyper
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. :)
// Note: awaiting this won't succeed until the handshake response has been returned to the client, so this must be | ||
// spawned on a separate task so as not to block that response being handed back. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is good, without this comment I'd have missed how this works.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks clean, just some notes on the accept key encoding :)
src/handshake.rs
Outdated
// writes the response that's expected to be handed back in the response header `Sec-WebSocket-Accept`. | ||
// | ||
// See https://datatracker.ietf.org/doc/html/rfc6455#section-1.3 for more information on this. | ||
fn generate_accept_key<'k>(key_base64: &[u8; 24], output_buf: &'k mut [u8; 32]) -> &'k [u8] { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FYI: there is a WebSocketKey
type alias defined here ([u8; 24]
): the hash is always 16 bytes, and base64 encoding of it is always 24 bytes. You could skip the output_buf
and just return WebSocketKey
by value here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the pointer! I am now returning a 28 (not 32) byte array rather than taking in a buffer. Unless I'm mistaken, base64 encoding a 160bit hash will always use exactly 28 bytes!
src/handshake/http.rs
Outdated
} | ||
|
||
// Pull out the Sec-WebSocket-Key and generate the appropriate response to it. | ||
let key: &[u8; 24] = match key.as_bytes().try_into() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could also use WebSocketKey
alias here.
This is an attempt to integrate some code behind an
http
feature flag which (hopefully) makes it much simpler to turnhttp::Request
s (such as thosehyper
hands out) into Soketto WebSocket connections.Have a look at the hyper example to see what making use of this would look like :)
Todo: