Skip to content

Reject response header blocks that don’t include the :status field - #311

Merged
Lukasa merged 12 commits into
python-hyper:masterfrom
sunu:issue-290
Sep 20, 2016
Merged

Lukasa merged 12 commits into
python-hyper:masterfrom
sunu:issue-290

Conversation

@sunu

@sunu sunu commented Sep 12, 2016

Copy link
Copy Markdown
Member

Fix for #290

Comment thread h2/stream.py Outdated
# an internal event, so we can do away with this branch.
is_trailer = False

is_response_header = is_response and not is_trailer

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

is_response should be completely determinable by the events. Do we really need the extra parameter?

@Lukasa

Lukasa commented Sep 12, 2016

Copy link
Copy Markdown
Member

Great start @sunu! So far this looks really good, I've left a few notes inline for you to look over.

@sunu

sunu commented Sep 13, 2016

Copy link
Copy Markdown
Member Author

Thanks for the review @Lukasa @alexwlchan. I've updated the PR addressing most of the comments.

Comment thread h2/stream.py Outdated
)
is_response_header = isinstance(
events[0], ResponseReceived
) and not self.state_machine.client

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Do we need this and not check? I believe that ResponseReceived can only fire when we are a client.

While we're here, I suspect we're going to need an internal-only _ResponseSent event, much like the _TrailersSent event you can see in the block above.

@Lukasa

Lukasa commented Sep 13, 2016

Copy link
Copy Markdown
Member

Great! I have left some more notes.

@alexwlchan alexwlchan changed the title Reject response header blocks that don’t include the field Reject response header blocks that don’t include the :status field Sep 14, 2016
Comment thread h2/utilities.py Outdated
u':status' not in seen_pseudo_header_fields
):
seen_status_field = (b':status' in seen_pseudo_header_fields or
u':status' in seen_pseudo_header_fields)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@sunu I believe that the parens on their own lines is actually a style thing for this project that @Lukasa prefers. You can see is working similarly on the conditional above.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Oops. Yeah, sorry about that. Will fix.

@sunu

sunu commented Sep 16, 2016

Copy link
Copy Markdown
Member Author

@Lukasa I have pushed some commits. But the test test_matching_authority_host_headers will fail for all cases where is_response_header is true, because headers doesn't contain :status.

So does it make sense to add :status to headers there? Does :authority header ever appear in a response?

@Lukasa Lukasa left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Awesome, one small comment change and then I think we're ready to go!

Comment thread h2/events.py
This is an internal event, used to determine validation steps on
outgoing header blocks.
"""
pass

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'd like at this point to also add a _RequestHeadersSent field. We don't have to do it as part of this PR, but can you open a new issue to track adding the new internal event? The lack of symmetry is making me sad. ;)

Comment thread test/test_basic_logic.py
c.initiate_connection()
c.send_headers(1, self.example_request_headers)
f = frame_factory.build_headers_frame(self.example_request_headers)
f = frame_factory.build_headers_frame(self.example_response_headers)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Heh, nice catch! That's a good validation that the new code is working as expected!

@Lukasa

Lukasa commented Sep 16, 2016

Copy link
Copy Markdown
Member

Response headers may never contain :authority.

@sunu

sunu commented Sep 16, 2016

Copy link
Copy Markdown
Member Author

Awesome, one small comment change and then I think we're ready to go!

@Lukasa which comment change are you refering to? (I have already added a comment about ResponseHeadersSent event if that's the one you're refering to)

Also, what about the failing test? :P

@sunu

sunu commented Sep 16, 2016

Copy link
Copy Markdown
Member Author

@Lukasa @nateprewitt Off topic but I get emails whenever you guys comment, but I can't find the last couple of comments on the Github ui anywhere (I tried for at least 5 minutes :P) Any idea what's going on?
Sorry for being a noob lol :P

@Lukasa

Lukasa commented Sep 16, 2016

Copy link
Copy Markdown
Member

Heh, sorry, they're in an outdated diff. If you scroll up a little bit you'll find a dropdown saying "x commented on an outdated diff": you want the one with lots of comments in it. ;)

@sunu

sunu commented Sep 16, 2016

Copy link
Copy Markdown
Member Author

@Lukasa PR updated

Comment thread test/test_invalid_headers.py Outdated
hdr_validation_flags):
def test_matching_authority_host_headers(
self, validation_function, hdr_validation_flags
):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Heh, sorry, I know that this isn't what you were told earlier, but the original style of this function was better. Basically, for function definitions I like having the argument names lined up, but for any other multiline sections I like having the parentheses by themselves.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Ok. fixed :)

@Lukasa Lukasa left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

One tiny comment note! We're nearly there!

Comment thread h2/stream.py Outdated
# Some state changes don't emit an internal event (for example,
# sending a push promise). We *always* emit an event for trailers,
# so the absence of an event means this definitely isn't a trailer.
# Similarly, we also emit an event whenever reponse headers are

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This should be response. =)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed :)

@alexwlchan alexwlchan left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Overall looks pretty good to me! Just a few minor suggestions.

Comment thread h2/utilities.py Outdated
)

# If ':status' pseudo-header is not there in a response header, reject it
seen_status_field = (

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I wonder if it’s worth moving the evaluation of seen_status_field into a conditional block that only runs if this is a response header, i.e.,

if hdr_validation_flags.is_response_header:
    seen_status_header = (...)
    if not seen_status_field:
        raise ProtocolError(...)

which saves us two unnecessary set lookups on request headers.

Comment thread test/test_invalid_headers.py Outdated
]
hdr_validation_response_headers = list(
filter(lambda flags: flags.is_response_header, hdr_validation_combos)
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

(Opinion) I’d prefer this as a list comprehension, as I think that’s easier to see at a glance what the condition is, i.e.,

hdr_validation_response_headers = [
    flags for flags in hdr_validation_combos
    if flags.is_response_header
]

and

hdr_validation_response_headers = [
    flags for flags in hdr_validation_combos
    if not (flags.is_trailer or flags.is_response_header)
]

but if @Lukasa is happy with list(filter(lambda(...))), I’ll shut up about it.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I have no problem with using a list comprehension.

Comment thread h2/utilities.py
seen_pseudo_header_fields
)

# If ':status' pseudo-header is not there in a response header, reject it

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

It would be nice if this comment had a reference to the exact RFC section – I know we‘ve not been super consistent on that point, but I think it’s helpful.

To save you looking it up again: RFC 7540 § 8.1.2.4.

https://tools.ietf.org/html/rfc7540#section-8.1.2.4

Comment thread h2/stream.py
events[0], (_TrailersSent, TrailersReceived)
)
is_response_header = isinstance(
events[0], (_ResponseHeadersSent, ResponseReceived)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

(Trivial) Seeing these side-by-side, I wonder if we should drop Headers from the name of this event, i.e., _ResponseSent. Better symmetry, and matches what I did for _TrailerSent.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Rather than deal with this in this ticket, let's open a new one related to this issue and #314 that refactors the event names.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Added as a comment on #314.

@Lukasa

Lukasa commented Sep 19, 2016

Copy link
Copy Markdown
Member

@sunu I'm aware that you're probably just taking a break, but as an FYI I'd like you to address @alexwlchan's reviews before I do another review. =)

@sunu

sunu commented Sep 20, 2016

Copy link
Copy Markdown
Member Author

@Lukasa @alexwlchan PR updated!

@alexwlchan alexwlchan left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Okay, all looks good to me!

Comment thread h2/stream.py
events[0], (_TrailersSent, TrailersReceived)
)
is_response_header = isinstance(
events[0], (_ResponseHeadersSent, ResponseReceived)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Added as a comment on #314.

@Lukasa Lukasa left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Excellent work! This looks great to me, I'm so delighted that you finished it up. ✨

@Lukasa

Lukasa commented Sep 20, 2016

Copy link
Copy Markdown
Member

Can you please merge in the latest master branch? I'd like to confirm that the tests still pass with it in place.

@sunu

sunu commented Sep 20, 2016

Copy link
Copy Markdown
Member Author

@Lukasa Done! :)

@Lukasa
Lukasa merged commit f4b2046 into python-hyper:master Sep 20, 2016
@sunu
sunu deleted the issue-290 branch September 20, 2016 19:37
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.

4 participants