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

All new headers should be RFC8941 Structured Field Values #255

Open
bblfish opened this issue Apr 16, 2021 · 2 comments
Open

All new headers should be RFC8941 Structured Field Values #255

bblfish opened this issue Apr 16, 2021 · 2 comments

Comments

@bblfish
Copy link
Member

bblfish commented Apr 16, 2021

I have just implemented an RFC8941 parser to support Signing Http Messages IETF draft, so I thought I'd pass on my new found knowledge here.

The Structured Header Fields RFC recommends all new headers to follow that standard. An overview of the reasons for it are given in this blog post. There are over 10 implementations in various languages listed here. And the IETF is working on a binary version at present so that headers can work better with HTTP/2 and HTTP/3.

One of the advantages is that it can make defining new header fields a lot easier, as well as allowing HTTP libraries to automatically parse new hearders on a first pass using that mode. It makes debugging easier too.

So given that and while it is fresh in my mind let me look at WAC-Allow with BNF

wac-allow        = "WAC-Allow" ":" OWS #access-param OWS
access-param     = permission-group OWS "=" OWS access-modes
permission-group = 1*ALPHA
access-modes     = DQUOTE OWS *1(access-mode *(RWS access-mode)) OWS DQUOTE
access-mode      = "read" / "write" / "append" / "control"

An example of such a header would be:

WAC-Allow: user="read write"
WAC-Allow: public="read"

The permission-group elements are instances of sf-token. The modes are instance of sf-string. There are two headers, which can be wrapped, so it must be possible to have those two fold into one header:

WAC-Allow: user="read write", public="read"

That key-value pair, where the keys are unique, indicates that we have an sfDictionary and indeed if I can parse it that way getting

ListMap(Token(user) -> PItem(SfString(read write),ListMap()), Token(public) -> PItem(SfString(read),ListMap()))

Instead of having a string of concatenated values one could use the Inner List structure of RFC8941 and so have headers like this:

WAC-Allow: user=("read" "write"), public=("read")

And that indeed parses to

ListMap(Token(user) -> IList(List(PItem(SfString(read),ListMap()), PItem(SfString(write),ListMap())),ListMap()), Token(public) -> IList(List(PItem(SfString(read),ListMap())),ListMap()))

The empty ListMap() just indicate that there are no attributes on the "read" or "write" sfStrings and no attributes on the IList either.

I am not sure if there is much gained by having the modes be strings. They could just as well be sf-tokens. In which case we would have

WAC-Allow: user=(read write), public=(read)

which parses to

ListMap(Token(user) -> IList(List(PItem(Token(read),ListMap()), PItem(Token(write),ListMap())),ListMap()), Token(public) -> IList(List(PItem(Token(read),ListMap())),ListMap()))

The output generated by the parser looks verbose, but it the implementations is reasonably efficient.

@bblfish
Copy link
Member Author

bblfish commented Apr 16, 2021

I have added the three examples above to my test suite

@bblfish
Copy link
Member Author

bblfish commented Jan 17, 2022

I have moved my implementation of the RFC8941 parser to it's own project in the httpSig repo.
It is write-in Scala and compiles to the JVM and to JS. (still working on pieces there).

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

No branches or pull requests

2 participants