Skip to content

Conversation

@AlanQuatermain
Copy link
Contributor

There's a public static creator which takes a ByteBuffer and array of HTTPHeader now, and the buffer and headers properties (and thus the HTTPHeader and HTTPHeaderIndex types) are public to support that.

Motivation:

HTTP/2 adds an additional item to a header key/value pair: its indexability. By default, headers can be inserted into the HPACK header table index; sometimes this will be denied (common case is 'content-length' header, which is rarely going to be the same, and will just cause the table to purge more often than is really necessary). Additionally, a header may be marked as not only non-indexable but also non-rewritable by proxies. HTTPHeaders provides nowhere to store this, so the HPACKHeaders implementation referenced in apple/swift-nio-http2#10 was created to add in that capability.

Now, given that we really want the HTTP version to be an implementation detail, we want to keep the HPACK details hidden, and would thus be using HTTPHeaders in client APIs. NIOHTTP2 already has a HTTP1-to-HTTP2 channel handler that translates between the two. Thus it behooves us to have the means to copy the actual key/value pairs between the two types without making a round-trip from UTF-8 bytes to UTF-16 Strings. These changes allow NIOHPACK or NIOHTTP2 to implement that round-trip internally.

Modifications:

  • HTTPHeader and HTTPHeaderIndex types are now public.
  • HTTPHeaders.buffer and HTTPHeaders.headers properties are now public.
  • A new static method, HTTPHeaders.createHeaderBlock(buffer:headers:) was created to serve as a public means to create a HTTPHeaders from a ByteBuffer from outside NIOHTTP1. @Lukasa suggested this should be a static method rather than an initializer.

Result:

Nothing in NIOHTTP1 changes in operation. All public types have documentation comments noting that they are only public for very specific reasons, and are not intended for general use. Once this is committed, NIOHPACK & NIOHTTP2 will be able to implement fast round-trips between HTTPHeaders and HPACKHeaders.

@swift-nio-bot
Copy link

Can one of the admins verify this patch?

1 similar comment
@swift-nio-bot
Copy link

Can one of the admins verify this patch?

Copy link
Contributor

@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.

One small note. We'll obviously end up wanting some tests for the new API surface area, but before you write them I want to get @weissi and @normanmaurer to weigh in here and express their opinions as to this API design. A few alternative possibilities that might be suggested:

  1. Don't expose the HTTPHeaderIndex and HTTPHeader types, instead just use list of tuples computed as needed.
  2. Rather than make buffer and headers public, use a with* function to expose them with limited scope and a stern admonition not to escape the buffer.

}

/// This is public to aid in the creation of supplemental HTTP libraries, e.g.
/// NIOHTTP2 and NIOHPACK. It is not intended for general use.
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 even though these things aren't for general use, we should explain what they are in the doc comments.

Copy link
Contributor

Choose a reason for hiding this comment

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

I'd still like an explanation in this function. 😄

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 this comment got lost in the file.

@AlanQuatermain
Copy link
Contributor Author

I like the idea of a with* function. I wasn't entirely certain how to couch things, so I went with the smallest actual API change.

@weissi
Copy link
Member

weissi commented Jul 30, 2018

thanks @AlanQuatermain! I'm not too fussed about exposing the HTTPHeaderIndex and HTTPHeader types but exposing buffer and headers directly (as properties) I find a little more troublesome. The reason is: If they're properties they should really be constant time and for those two that means our implementation then needs to always back them by a ByteBuffer. For a with* function that's not the case so I think I'd prefer that too.

@AlanQuatermain
Copy link
Contributor Author

Cool, I'll update this to use the with* approach.

Copy link
Contributor

@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, I'm happy with this API. Now all we need is some tests, as well as a quick bit of elaboration on the doc comments.

}

/// This is public to aid in the creation of supplemental HTTP libraries, e.g.
/// NIOHTTP2 and NIOHPACK. It is not intended for general use.
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd still like an explanation in this function. 😄

/// characters.
/// - locations: An array of `HTTPHeader`s, each of which contains information on the location in
/// the buffer of both a header's name and value.
/// - contiguous: A `Bool` indicating whether the headers are stored contiguously, with no gaps between
Copy link
Contributor

Choose a reason for hiding this comment

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

Does this render properly? My assumption is that it does not, that these parameter meanings need to be documented in the text for block.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yep, it does. I had to do some digging to find out the proper layout, but it transpires you just have to give the block parameters names and include then with the method's parameters. They render correctly in a separate table in the block parameter's documentation.

/// - locations: An array of `HTTPHeader`s, each of which contains information on the location in
/// the buffer of both a header's name and value.
/// - contiguous: A `Bool` indicating whether the headers are stored contiguously, with no gaps between
/// adjacent name/value pairs.
Copy link
Contributor

Choose a reason for hiding this comment

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

Do you mind elaborating on this last parameter? Specifically, there are gaps, but those gaps correspond to a HTTP/1.1-formatted header block (that is, the gaps are either : or \r\n in the buffer).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Argh, I'd forgotten in contained those. I was thinking of the continuous property that is marked false when something is removed from the buffer, i.e. when the buffer also contains strings that aren't intended to be included in the header list. In other words, whether the buffer can be directly copied.

In retrospect, it doesn't really match my intended use case (i.e. whether HPACKHeaders can just grab the buffer directly without caring about copying extra data—since the HPACK structure isn't supporting the same add/remove functionality and would like a smaller storage load). However, it still seems useful since it can tell receivers if the buffer is already a valid encoded HTTP/1 header block, ready for the wire as-is.

Copy link
Contributor

@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.

One minor change and then I'm happy.

}

/// This is public to aid in the creation of supplemental HTTP libraries, e.g.
/// NIOHTTP2 and NIOHPACK. It is not intended for general use.
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 this comment got lost in the file.

@AlanQuatermain
Copy link
Contributor Author

Le oops. Duly excised 😊

@Lukasa
Copy link
Contributor

Lukasa commented Aug 3, 2018

@swift-nio-bot test this please

@Lukasa
Copy link
Contributor

Lukasa commented Aug 3, 2018

Looks like we're missing the Linux tests. @AlanQuatermain, you may find it useful to place the following file at .git/hooks/pre-commit in the repository:

#!/bin/sh

FIRST_OUT="$(git status --porcelain)"
ruby scripts/generate_linux_tests.rb > /dev/null
NEW_OUT="$(git status --porcelain)"

if [[ "$FIRST_OUT" != "$NEW_OUT" ]]; then
    printf "\033[0;31mMissing linux test changes!\033[0m\n"
    printf "The appropriate changes have been left in the repo.\n"
    printf "Please fix up and then merge.\n"
    exit 1
fi

@AlanQuatermain
Copy link
Contributor Author

@swift-nio-bot test this please

Copy link
Member

@weissi weissi left a comment

Choose a reason for hiding this comment

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

thanks! That looks good to me now!

@weissi
Copy link
Member

weissi commented Aug 4, 2018

@swift-nio-bot test this please

@weissi weissi added the 🆕 semver/minor Adds new public API. label Aug 4, 2018
Lukasa added a commit to Lukasa/swift-nio that referenced this pull request Aug 6, 2018
Motivation:

The CONTRIBUTORS file is getting out-of-date quickly, and we forget
to update it. We should make updating it part of the contribution flow
such that it remains current.

I noticed this because it got picked up in apple#525.

Modifications:

- Added a check to the sanity script to validate the CONTRIBUTORS
  file is up-to-date.
- Updated the mailmap file because @weissi doesn't know how to spell
  his own name.
- Minor clean up in the sanity script to handle the fact it checks
  three programming languages, so the output is a bit better.

Result:

Better sanity checking.
Copy link
Contributor

@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.

One minor note and then I'm happy! ✨

CONTRIBUTORS.txt Outdated
- Ian Partridge <i.partridge@uk.ibm.com>
- Jason Toffaletti <toffaletti@gmail.com>
- Jim Dovey <jimdovey@mac.com>
- Johannes Weiss <johannesweiss@apple.com>
Copy link
Contributor

Choose a reason for hiding this comment

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

Let's remove the contributors script, as it has inadvertently added Johannes twice. We should re-run it in a separate PR, and then add it to our sanity check build system to start rejecting builds where the user is not in the contributor mesh.

Copy link
Contributor

Choose a reason for hiding this comment

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

Ok, see #550 for this. You should leave your own name's entry here in the right place, as that will prevent us hitting a problem if we end up merging #550 before this patch.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hehe, I was going to suggest the .mailmap thing—I saw the same in the http2 repo, and that the .mailmap file there had two entries for @weissi that were the wrong way round, it seems. I copied his approach first, but then that didn't work so I copied yours 😉

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've simply reverted the Contributors file changes; if the script will be run & inlined with the build or merge process then that should be handled by something other than my commit, I think. I expect Github provides something like a post-pull-request-approval hook that could be used to automate the process?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh, wait, I mis-read. So I should update the contributors file but manually delete @weissi's ASCII clone—no problem.

Copy link
Contributor

Choose a reason for hiding this comment

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

Sorry, no, you were right the first time: let's remove the entire CONTRIBUTORS file change except your entry.

Copy link
Member

Choose a reason for hiding this comment

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

sorry guys 😬. I recently had too much trouble with 'Weiß' so switched to 'Weiss' everywhere 🙃.

@Lukasa
Copy link
Contributor

Lukasa commented Aug 6, 2018

Having @AlanQuatermain on the whitelist should mean we don't have to prompt the bot to build anymore, it should auto-build all of @AlanQuatermain's PRs on this repo.

@Lukasa
Copy link
Contributor

Lukasa commented Aug 6, 2018

Oh wait, he isn't on the whitelist here.

@Lukasa
Copy link
Contributor

Lukasa commented Aug 6, 2018

@swift-nio-bot add to whitelist

Lukasa added a commit to Lukasa/swift-nio that referenced this pull request Aug 6, 2018
Motivation:

The CONTRIBUTORS file is getting out-of-date quickly, and we forget
to update it. We should make updating it part of the contribution flow
such that it remains current.

I noticed this because it got picked up in apple#525.

Modifications:

- Added a check to the sanity script to validate the CONTRIBUTORS
  file is up-to-date.
- Updated the mailmap file because @weissi doesn't know how to spell
  his own name.
- Minor clean up in the sanity script to handle the fact it checks
  three programming languages, so the output is a bit better.

Result:

Better sanity checking.
@Lukasa
Copy link
Contributor

Lukasa commented Aug 8, 2018

@AlanQuatermain Looks like we have some merge conflicts: can you fix those up and re-push? Then we should be able to land this.

@Lukasa Lukasa added this to the 1.10.0 milestone Aug 8, 2018
@AlanQuatermain
Copy link
Contributor Author

Face → palm. So much annoying commit replication there. Sigh. If only there were a way to rebase these things cleanly, without generating weird commit histories. I would squash all this if I though that would actually not cause even more problems when I try to push it to my own repo; the pull-request model kinda breaks when you need to have two repositories (local and Github) that need to rebase when there's a merge conflict.

The `HTTPHeaders` API now vends `withUnsafeBufferAndIndices(_:)` and a static factory method to create `HTTPHeaders` from a `ByteBuffer` and a list of `HTTPHeader` values. Tests have been added, and the contributor script manually updated.
@AlanQuatermain
Copy link
Contributor Author

Boom. Damned thing. Made a new branch based on apple/master, merge-squashed my changes onto that, hard-reset master back to 57c6724, then force-pushed.

Single. Commit.

*mic drop*

@AlanQuatermain
Copy link
Contributor Author

For the record, there was a chain of about 50 commits, many of which were identical due to multiple merges/rebases, before the merge-squash created one very small commit containing only the actual changes for this PR. Sigh.

@Lukasa Lukasa merged commit 5279d73 into apple:master Aug 9, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🆕 semver/minor Adds new public API.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants