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

Expose zero-copy-ish headers on ClientRequest #35

Merged
merged 18 commits into from
Jun 11, 2021
Merged

Conversation

maciejhirsz
Copy link
Contributor

@maciejhirsz maciejhirsz commented Jun 10, 2021

Alternative to #34.

I hope @tomaka can appreciate the number of hoops I had to jump through to get this to work properly. The way headers were previously parsed totally screwed with lifetimes here and prevented zero-copy header exposure (also the reason why path was previously an owned String).

What made this possible is realization that WebSocket handshake request does not contain body, thus we can safely borrow stuff from the buffer until a response needs to be sent (at which point buffer is cleared regardless).

Side effect: removed two allocations from request handling, not that it was a bottleneck, but hey.

BREAKING CHANGES:

  • ClientRequest::path() will default to "\" if omitted in request (was empty string).
  • ClientRequest::key() now returns WebSocketKey (alias of [u8; 24]), was &[u8].
  • ClientRequest::into_key() is gone.
  • Response::Accept's key field is now WebSocketKey (alias of [u8; 24]), was &[u8].
  • handshake::Error has new variants.
  • Server::receive_request() will only attempt to read headers up to 8KiB.

ADDED

  • ClientRequest::headers() returns a new RequestHeaders struct with host and origin fields, exposing the Host and Origin header values (&[u8] and Option<&[u8]> respectively).

loop {
crate::read(&mut self.socket, &mut self.buffer, BLOCK_SIZE).await?;
if let Parsing::Done { value, offset } = self.decode_request()? {
self.buffer.advance(offset);
Copy link
Contributor Author

@maciejhirsz maciejhirsz Jun 10, 2021

Choose a reason for hiding this comment

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

This mutable borrow of self.buffer prevented us from borrowing stuff in return value. The advance was not necessary since the buffer is never read after the headers (not just that, it should not contain any bytes after the request AFAIU).

loop {
crate::read(&mut self.socket, &mut self.buffer, BLOCK_SIZE).await?;
if let Parsing::Done { value, offset } = self.decode_request()? {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Attempting decode after each read also made lifetimes convoluted since there is a mutable borrow to self.buffer made on every iteration. Opted to do a single parse after we are sure headers are complete in the new code.

@maciejhirsz maciejhirsz mentioned this pull request Jun 10, 2021
Closed
Copy link
Contributor

@dvdplm dvdplm left a comment

Choose a reason for hiding this comment

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

This should work, nice job. :)

@maciejhirsz maciejhirsz requested a review from jsdw June 10, 2021 18:51
Copy link
Contributor

@tomaka tomaka left a comment

Choose a reason for hiding this comment

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

I would have a lot to nit-pick, but I won't bother you more

@maciejhirsz maciejhirsz merged commit b18992e into develop Jun 11, 2021
@maciejhirsz maciejhirsz deleted the mh-expose-headers branch June 11, 2021 08:25

// Give up if we've reached the limit. We could emit a specific error here,
// but httparse will produce meaningful error for us regardless.
if limit == MAX_HEADERS_SIZE {
Copy link
Member

Choose a reason for hiding this comment

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

ok, this will also emit an error if self.buffer.len() > MAX_HEADER_SIZE?

it's truncated below by std::cmp::min a couple lines above

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.

5 participants