Skip to content

Conversation

@haikuginger
Copy link
Contributor

This PR adds the ExtensionFrame object, which hyperframe can use to denote a frame whose identifier code isn't known to the package. This can be used in upstream consumers which do know the semantic meaning of that particular identifier code.

Copy link
Contributor

@alexwlchan alexwlchan left a comment

Choose a reason for hiding this comment

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

A few minor comments, but otherwise this looks pretty good to me.

Thanks for getting started on this!


@staticmethod
def parse_frame_header(header):
def parse_frame_header(header, strict=False):
Copy link
Contributor

Choose a reason for hiding this comment

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

Please add a docstring comment to explain the new parameter.

stream_id = fields[4]

if type not in FRAMES:
if not strict:
Copy link
Contributor

Choose a reason for hiding this comment

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

This is purely preference, but I’d have done this as:

if strict: raise UnknownFrameError return ExtensionFrame

because we expect strict=True to be the unusual path – or at least, it seems so, given we default to False.

(I don‘t care if you change this or not, just noting my feelings.)

Although certain byte prefixes are ordained by specification to have
certain contextual meanings, frames with other prefixes are not prohibited,
and may be used to communicate arbitrary meaning between HTTP 2 peers.
Copy link
Contributor

Choose a reason for hiding this comment

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

Nitpick: it’s “HTTP/2”, not “HTTP 2”.

(No, I don’t know why either.)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Will fix.

@@ -1,4 +1,6 @@
# -*- coding: utf-8 -*-
from hyperframe.flags import Flag

Copy link
Contributor

Choose a reason for hiding this comment

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

Nitpick: any reason for the empty line?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Nope. Completely stylistic.

f, l = Frame.parse_frame_header(
b'\x00\x00\x59\xFF\x00\x00\x00\x00\x01'
)
assert f.type == 0xFF
Copy link
Contributor

Choose a reason for hiding this comment

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

I think we could additionally have

assert isinstance(f, ExtensionFrame)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Will add.

@haikuginger
Copy link
Contributor Author

@alexwlchan, I believe I've addressed your comments.

Copy link
Member

@Lukasa Lukasa left a comment

Choose a reason for hiding this comment

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

Cool, this is generally looking pretty good! I have left some notes inline.

Takes a 9-byte frame header and returns a tuple of the appropriate
Frame object and the length that needs to be read from the socket.
This populates the flags field, and determines how long the body is.
Copy link
Member

Choose a reason for hiding this comment

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

Can you add a versionchanged stanza in this docstring to indicate what version we changed this and what the change was? In this case, the version we changed it would be 5.0.0.

flag_byte=flags,
stream_id=stream_id,
)
return (frame, length)
Copy link
Member

Choose a reason for hiding this comment

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

So, for the sake of clarity, let's actually do this:

try: frame = FRAMES[type](stream_id) except KeyError: if strict: raise UnknownFrameError(type, length) frame = ExtensionFrame(type=type, stream_id=stream_id)

Then, the flag byte can end up in place using parse_flags, and we can reduce the amount of return points.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

So, I don't think we can actually use parse_flags here. parse_flags depends on us having a definition of which flags are available. Since the meaning of the flags is defined on a per-frame basis, the base ExtensionFrame doesn't have the ability to do that.

The assign_flag_mapping method lets us do that after the fact - an upstream consumer, which is interpreting the frame, can insert a mapping between bit location and flag name, resulting in the frame getting a flags member.

Copy link
Member

Choose a reason for hiding this comment

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

So I am not sure that assign_flag_mapping is a good idea tbh. I think that realistically anyone who wants to interpret the body of a new frame has to handle basically everything except the parsing of the frame header. So I'd be happy to just have us save the flag_byte and call it a day.

Thus, hyperframe, rather than raising an exception when such a frame is
encountered, wraps it in a generic frame to be properly acted upon by
upstream consumers which might have additional context on how to use it.
"""
Copy link
Member

Choose a reason for hiding this comment

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

Can you add a versionadded stanza to this docstring?

"""
self.defined_flags = flags
self.flags = Flags(self.defined_flags)
return self.parse_flags(self.flag_byte)
Copy link
Member

Choose a reason for hiding this comment

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

I don't think we need this method.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

See comment above.

)
assert f.body == b'hello world!'
assert f.body_len == 12

Copy link
Member

Choose a reason for hiding this comment

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

Can at least one of these tests validate that the stream id is correct?

@haikuginger
Copy link
Contributor Author

@Lukasa, addressed a couple of your comments and responded on a couple other.

flag_byte=flags,
stream_id=stream_id,
)
return (frame, length)
Copy link
Member

Choose a reason for hiding this comment

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

So I am not sure that assign_flag_mapping is a good idea tbh. I think that realistically anyone who wants to interpret the body of a new frame has to handle basically everything except the parsing of the frame header. So I'd be happy to just have us save the flag_byte and call it a day.

@Lukasa Lukasa merged commit 32d01bf into python-hyper:master Mar 7, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

3 participants