Skip to content
This repository has been archived by the owner on Jan 13, 2021. It is now read-only.

Check if length of frame is valid #135

Closed
wants to merge 23 commits into from

Conversation

jdecuyper
Copy link
Contributor

Fix for #69

  • Before processing a frame, check if its length is valid using the range defined by the spec.
  • Allow endpoint to update the max frame size setting.

When receiving a frame from endpoint, check if length of frame is below the maximum size setting. If frame size is invalid then send a reset frame to endpoint. Add method to the connection class that sends a reset frames with an error code.
If the setting frame contains a new valid max frame size then update hyper's settings. Add tests to confirm that this setting is updated only with values between the accepted range.
frame.stream_id,
length,
frame_size
)
Copy link
Member

Choose a reason for hiding this comment

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

It'd be safer to log first, I think: that way the log is emitted before we explode due to any traceback.

Copy link
Member

Choose a reason for hiding this comment

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

Oh, this check also isn't right. The value in self._settings[] is not a limit on the frame size the other side can emit, it's a limit on the size it can receive. hyper doesn't currently make the max frame size it can tolerate configurable (and I don't really feel like it should at this stage), so I think we just want to confirm that we tolerate MAX_FRAME_SIZE frames.

We then want to add a similar check to our own code for sending.

@Lukasa
Copy link
Member

Lukasa commented May 29, 2015

Brilliant stuff @jdecuyper! Great start. I've made some notes inline. =)

When hyper is sending a frame, it should validate its length against the constant MAX_FRAME_SIZE and not the endpoint's settings. Add error code parameter to the connection's close method. Check if socket is still alive before sending an ACK to the endpoint. Fix minor spelling errors.
@jdecuyper
Copy link
Contributor Author

@Lukasa just to make sure I understand this right, when serializing a frame, we should be checking the length of the body against the maximum frame size. I think it would be nicer to apply this check when calling serialize from the send data callback. Is it okay to have serialize also return the body length?

new_size)
# Tear the connection down with error code PROTOCOL_ERROR
self.close(1)

Copy link
Member

Choose a reason for hiding this comment

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

I think, rather than tie ourselves in knots trying to handle teardown mid-connection, we should throw exceptions whenever we have to tear a connection down ourselves. That means, still call self.close(), but then immediately throw an exception.

While we're here, it might be good to define an exception that we throw whenever we encounter a HTTP/2 connection error.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We have already such an exception available so I have used that one.

@Lukasa
Copy link
Member

Lukasa commented May 31, 2015

@jdecuyper That sounds reasonable to me =)

@jdecuyper
Copy link
Contributor Author

Have that function serialize return 2 values was breaking too many existing code so I took a different approach and expose the length of the body through self.body_len.

@@ -63,7 +65,7 @@ def parse_flags(self, flag_byte):

def serialize(self):
body = self.serialize_body()
body_len = len(body)
self.body_len = len(body)
Copy link
Member

Choose a reason for hiding this comment

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

Let's make sure we initialise this to zero in __init__.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

All set! Anything else I should cover?

@@ -482,6 +497,9 @@ def _send_cb(self, frame, tolerate_peer_gone=False):

data = frame.serialize()

if frame.body_len > FRAME_MAX_LEN: # pragma: no cover
Copy link
Member

Choose a reason for hiding this comment

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

So this is the point where we need to abort based on the set max frame size. Can you change this check to do that?

Copy link
Member

Choose a reason for hiding this comment

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

Sorry about having to make this note. I've had lots of trouble in the past keeping track of which setting applies to which direction in the communication, so I'm not entirely surprised that we've had to go back and forth on this a few times.

Copy link
Member

Choose a reason for hiding this comment

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

I also don't think there's any good reason to #pragma: no cover this, we can hit it pretty directly to prove the case.

@Lukasa
Copy link
Member

Lukasa commented Jun 21, 2015

@jdecuyper What's the status here?

@jdecuyper
Copy link
Contributor Author

Status is: will work on fixes tomorrow if that's alright :)

@Lukasa
Copy link
Member

Lukasa commented Jun 23, 2015

Sure thing. =) There's no rush, just wanted to make sure this didn't get lost! 👍

When sending a frame to the server, care must be taken to not exceed the maximum frame size setting. If the size is higher than the defined setting then a ValueError is thrown.
@jdecuyper
Copy link
Contributor Author

@Lukasa
When sending a frame, the size is checked against the maximum frame size setting (which can be updated by the server). As you asked, I have also added a test for this case.

@jdecuyper
Copy link
Contributor Author

Cool! Curious to see what the fix is about =)
In the meantime I have create the PR: python-hyper/hyperframe#2

@Lukasa
Copy link
Member

Lukasa commented Jun 28, 2015

The fix already landed, see python-hyper/hyperframe@2363947.

If you rebase on top of development you should find the code you need has been vendored in from hyperframe. =D

When receiving a frame from endpoint, check if length of frame is below the maximum size setting. If frame size is invalid then send a reset frame to endpoint. Add method to the connection class that sends a reset frames with an error code.
If the setting frame contains a new valid max frame size then update hyper's settings. Add tests to confirm that this setting is updated only with values between the accepted range.
When hyper is sending a frame, it should validate its length against the constant MAX_FRAME_SIZE and not the endpoint's settings. Add error code parameter to the connection's close method. Check if socket is still alive before sending an ACK to the endpoint. Fix minor spelling errors.
When sending a frame to the server, care must be taken to not exceed the maximum frame size setting. If the size is higher than the defined setting then a ValueError is thrown.
@jdecuyper
Copy link
Contributor Author

@Lukasa the rebase worked, let me know if it looks alright to you!

@Lukasa
Copy link
Member

Lukasa commented Jun 29, 2015

This is generally good, though the commit log has gone a bit wacky. Do you feel comfortable enough in git to fix it up, or do you want me to handle that on my end?

@jdecuyper
Copy link
Contributor Author

Sorry to bother you with this, it would be great if you could help me out here and even better if you could explain how you do it (if you have some time of course). Thanks!

@Lukasa
Copy link
Member

Lukasa commented Jun 29, 2015

Of course! I'll see if I can screen record the fix.

@sigmavirus24
Copy link
Contributor

Asciinema is pretty great fwiw

@Lukasa
Copy link
Member

Lukasa commented Jun 29, 2015

@jdecuyper The fix was easy, as you can see here. All I did was take the last commit that contained actual work from you (a031605) and merge it into the development branch. In that video you can see me scrolling down the terminal to ensure that none of your commits are there twice, which they aren't, so we know we're good.

Lukasa added a commit that referenced this pull request Jun 29, 2015
@Lukasa
Copy link
Member

Lukasa commented Jun 29, 2015

Alrighty, merged manually. Thanks @jdecuyper!

@Lukasa Lukasa closed this Jun 29, 2015
@jdecuyper jdecuyper deleted the max-frame-size branch June 29, 2015 20:43
@jdecuyper
Copy link
Contributor Author

@Lukasa many thanks for taking the time to explain 👍 👍

@jdecuyper
Copy link
Contributor Author

And btw thanks for the mentions in the v0.4.0 release notes =)

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants