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

Specify the HTTP Gateway protocol #20

Merged
merged 14 commits into from
May 3, 2022

Conversation

nomeata
Copy link
Contributor

@nomeata nomeata commented Apr 1, 2022

We have had the HTTP gateway for a while now, but

  • we didn’t have a public record of the expected Canister interface, with the authorative Candid fragment
  • we already have multiple implementations (icx-proxy and the service worker), and people we looking at the implementations to understand how thing work.
  • we see new features being implemented in one, but not the other implementation, and they start to diverge
  • some features are only implementation-defined (e.g. the certification fallback to index.html)
  • the interaction of new features (e.g. certificate, upgrade to update and streaming) is ill or at least vaguely defined.

So I think we urgently need a proper specification for the HTTP Gateway protocol, and a place to host this. The IC Interface Spec is a natural place, so here is a possible start.

This PR is descriptive, not prescriptive, with regard to the status quo: I (try to) specify the existing behavior of our Gateway implementations, not define a new and different protocol.

Preview available, pushed manually until #9 or similar has been fixed.

@nomeata
Copy link
Contributor Author

nomeata commented Apr 1, 2022

Draft until external contributions are possible.

@paulyoung, can you also review this? It would be helpful if you could double check this. Who else should be pinged?

@nomeata
Copy link
Contributor Author

nomeata commented Apr 1, 2022

@jplevyak, right now the spec says that all headers are passed through by the boundary node, but that’s not really true, is it? What header filtering/mangling/addition should we specify/document here?

spec/index.adoc Outdated Show resolved Hide resolved
spec/index.adoc Outdated Show resolved Hide resolved
spec/index.adoc Outdated
|identity | rdmx6-jaaaa-aaaaa-aaadq-cai
|nns | qoctq-giaaa-aaaaa-aaaea-cai
|dscvr | h5aet-waaaa-aaaab-qaamq-cai
|personhood | g3wsl-eqaaa-aaaan-aaaaa-cai

Choose a reason for hiding this comment

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

Where is personhood specified?

I don't see it here.

Not really convinced this canister resolution belongs in the HTTP Gateway protocol, although it is good to know in general I suppose.

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 saw it for the first time yesterday in https://github.com/dfinity/ic/blob/a254116be472f81b85b76429ac8d987f80dd4411/typescript/service-worker/src/sw/http_request.ts#L17. I'll leave it to the Dfinity people to say if this should be there or not. But it demonstrates the need for a authorative list, at least until we have a dynamic system in place.

spec/index.adoc Outdated Show resolved Hide resolved
spec/index.adoc Outdated Show resolved Hide resolved
spec/index.adoc Outdated Show resolved Hide resolved
status_code: nat16;
headers: vec HeaderField;
body: blob;
upgrade : opt bool;

Choose a reason for hiding this comment

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

Typo: upgrade -> update

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Unfortunately(?) this field is called upgrade, as in “upgrade the call from query to an update call”. Very confusing… oh well.

See https://github.com/dfinity/icx-proxy/pull/6/files#diff-42cb6807ad74b3e201c5a7ca98b911c5fa08380e942be6e4ac5807f8377f87fcR259

Copy link
Contributor

Choose a reason for hiding this comment

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

Probably to late to change, but would promote be a better name?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Probably. Or resend_as_update_call. Or, in line with the pattern for the streaming callback, it could even pass a func ref.

In a way it's not too late: we can change this while keeping backward conpat in the implementations (there is only one so far) relatively easily (the proxy can simply keep both in it's internal expected type). I just wonder if we should do it with this PR, or maybe as a separate step, to get this in first.

spec/http-gateway.did Outdated Show resolved Hide resolved
spec/index.adoc Show resolved Hide resolved
service : {
http_request: (request: HttpRequest) -> (HttpResponse) query;
http_request_update: (request: HttpRequest) -> (HttpResponse);
}

Choose a reason for hiding this comment

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

I think it'd be clearer to make reference to the streaming callback here, but I understand why you didn't. (It's optional and also dynamically specified in HttpResponse.)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The name is arbitrary, right? So I wouldn't quite know how to include it.

@jplevyak
Copy link
Contributor

jplevyak commented Apr 2, 2022

@frederikrothenberger and @Daniel-Bloom-dfinity are current working this.


* The HTTP response status code is taken from the `status_code` field.

* The HTTP response headers are taken from the `headers` field.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Is the boundary node mangling or filtering the headers in any way that should be noted here?

Choose a reason for hiding this comment

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

The filtering we have is in dfinity/ic/ic-os/boundary-guestos/rootfs/etc/nginx/conf.d/001-ic-nginx.conf.

The short of it is we add these response headers (and thus their implications) to every HTTP call response:

access-control-allow-origin: *
access-control-allow-methods: GET, POST, HEAD, OPTIONS
access-control-allow-headers: DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Cookie
access-control-expose-headers: Content-Length,Content-Range
x-cache-status: MISS

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 guess the question is: Why set these? Shouldn’t the canister have control over them?

Choose a reason for hiding this comment

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

The short answer is "it's complicated". The longer answer is "because headers are not yet certified". As such we currently limit headers a bit to improve security. Once we get certified headers, we should not have any more need for this limitation.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok, good enough for this PR I guess.

@origyndev
Copy link

If we are making suggestions here I’d love for there to be a “return and upgrade” feature that returns the result of the query to the client but then calls update for recording the serving of the request in the canister. The reply to this call can be discarded as the request has already been served.

@nomeata
Copy link
Contributor Author

nomeata commented Apr 2, 2022

If we are making suggestions here

I suggest we don't, for now. Let's focus in finalizing a spec for the status quo. Might be hard enough.

Once thats done additional changes can be nicely discussed in their own PRs against master. Or maybe on the forum first.

@nomeata
Copy link
Contributor Author

nomeata commented Apr 5, 2022

I’ve manually pushed a rendering of this to netlify, to get a preview until #9 or similar has been fixed.

@paulyoung
Copy link
Contributor

paulyoung commented Apr 6, 2022

I'll try to review this soon but in the meantime I wanted to share https://forum.dfinity.org/t/boundary-node-http-response-headers/10747 in case it's of interest or provides some additional insight.

Who else should be pinged?

Based on the above I think @lastmjs would be interested in this.

spec/index.adoc Outdated Show resolved Hide resolved
spec/index.adoc Outdated Show resolved Hide resolved
spec/index.adoc Outdated Show resolved Hide resolved
spec/index.adoc Outdated Show resolved Hide resolved
spec/index.adoc Outdated Show resolved Hide resolved
spec/index.adoc Outdated Show resolved Hide resolved
spec/index.adoc Outdated Show resolved Hide resolved
spec/index.adoc Outdated Show resolved Hide resolved
spec/index.adoc Outdated Show resolved Hide resolved
spec/index.adoc Outdated Show resolved Hide resolved
Co-authored-by: Paul Young <84700+paulyoung@users.noreply.github.com>
@dfinity-droid-prod
Copy link

Dear @nomeata,

In order to potentially merge your code in this open-source repository and therefore proceed with your contribution, we need to have your approval on DFINITY's CLA1.

If you decide to agree with it, please visit this issue and read the instructions there.

— The DFINITY Foundation

Footnotes

  1. Contributor License Agreement

@paulyoung
Copy link
Contributor

Pinging @SuddenlyHazel for visibility since this set of functionality came up in conversations today.

@nomeata
Copy link
Contributor Author

nomeata commented Apr 9, 2022

Ok, with the CLA requirement out of the way, this could now be merged. Who on the DFINITY side is owning the process of shepherding and eventually merging community contributions? @Dfinity-Bjoern?

@jwiegley
Copy link
Contributor

@nomeata It is Björn and myself.

@Ali-Piccioni
Copy link
Contributor

update cla


2. The value of the header must be a structured header according to RFC 8941 with fields `certificate` and `tree`, both being byte sequences.

3. The `certificate` must be a valid certificate as per <<certification>>, signed by the root key. If the certificate contains a subnet delegation, the delegation must be valid for the given canister. The timestamp in `/time` must be recent. The subnet state tree in the certificate must reveal the canister’s <<state-tree-certified-data,certified data>>.

Choose a reason for hiding this comment

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

Currently neither icx-proxy nor the service worker check the certificate /time (which is bad). Can you give some more specific measure of "recent"? 5 minutes?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That’s probably for the security team to decide. 5 min should be ample (until we get into edge node caching, then things become tricky, because a cache is hardly different from an attacker serving old data).

Copy link
Member

@frederikrothenberger frederikrothenberger left a comment

Choose a reason for hiding this comment

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

Thanks for writing this spec.

dfinity-bot pushed a commit to dfinity/ic that referenced this pull request Apr 22, 2022
service-worker: implement support for upgrade flag

Implements support for the `upgrade` flag as per HTTP gateway specification: dfinity/interface-spec#20 

See merge request dfinity-lab/public/ic!4476
Copy link
Member

@Dfinity-Bjoern Dfinity-Bjoern left a comment

Choose a reason for hiding this comment

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

That's great! Thank you very much @nomeata for contributing this!

@nomeata
Copy link
Contributor Author

nomeata commented May 3, 2022

Note that I am not allowed to merge, so someone else will have to press that button (and ideally presses the “Squash and merge” button and manually cleans up the PR description or copies the PR description into the commit message – mergify would do that for us but that’s not enabled at the moment.)

@jwiegley jwiegley merged commit a6c6f1c into dfinity:master May 3, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.