Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ dist/
pocket-ic
.env
Cargo.lock
.wrangler
Copy link
Member Author

Choose a reason for hiding this comment

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

This folder is generated by Cloudflare's wrangler CLI


.DS_Store
.idea
5 changes: 2 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,9 @@ You can read more about this protocol in [the spec](https://github.com/dfinity/i

## Related Projects

- [Response Verification](https://github.com/dfinity/response-verification/)
- [Service Worker](https://github.com/dfinity/ic/tree/master/typescript/service-worker)
- [ICX Proxy](https://github.com/dfinity/ic/tree/master/rs/boundary_node/icx_proxy)
- [ic-gateway](https://github.com/dfinity/ic-gateway)
- [Desktop HTTP Proxy](https://github.com/dfinity/http-proxy)
- [Response Verification](https://github.com/dfinity/response-verification)

## Contributing

Expand Down
19 changes: 19 additions & 0 deletions examples/http-gateway/cloudflare/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Cloudflare Worker based ICP HTTP Gateway
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: it seems to me "based" should be preceded with a hyphen, but am not sure whether it should be "Cloudflare-Worker-based" or "Cloudflare Worker-based" (and obviously I'm not a native speaker 😢 ). Maybe the best solution would be to reformulate to "An ICP HTTP Gateway based on a Cloudflare Worker"?


## Environment variables

Set the `API_GATEWAY` and `CANISTER_ID` variables in the `wrangler.json` file. Run `pnpm run -F http-gateway-cloudflare-example cf-typegen` to regenerate the `worker-configuration.d.ts` file.

## Notes

- Do not alter the response body, status codes or headers in any way. Local HTTP Gateways on an end user's computer may re-validate the response and reject it if it has been altered.

## Possible optimizations

- Early hints:
- https://developers.cloudflare.com/workers/examples/103-early-hints/.
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Link.
- Link headers should be set on the canister side and certified. The implementation of this will depend on the frontend framework and bundler that is used.
- Cache control:
- Cloudflare reads the `Cache-Control` header and caches the response based on the value of the header.
- This header should be completely controlled by the canister.
16 changes: 16 additions & 0 deletions examples/http-gateway/cloudflare/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"name": "http-gateway-cloudflare-example",
"version": "0.0.0",
"private": true,
"scripts": {
"start": "wrangler dev",
"deploy": "wrangler deploy",
"cf-typegen": "wrangler types"
},
"dependencies": {
"@dfinity/http-gateway": "workspace:*"
},
"devDependencies": {
"wrangler": "^4.14.3"
}
}
40 changes: 40 additions & 0 deletions examples/http-gateway/cloudflare/src/index.ts
Copy link
Member Author

Choose a reason for hiding this comment

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

This is the main logic for the Cloudlfare worker.

Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { HttpGatewayClient } from '@dfinity/http-gateway';
import { HttpAgent } from '@dfinity/agent';
import RESPONSE_VERIFICATION_WASM from '@dfinity/response-verification/dist/web/web_bg.wasm';
Copy link
Member Author

Choose a reason for hiding this comment

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

I had issues with loading the WASM when the HTTP Gateway library did it internally. This should work fine in other environments, but Cloudflare doesn't like it for some reason. Loading it explicitly inside the worker and passing it as a parameter works well, although I really don't like it.


export default {
async fetch(request, env): Promise<Response> {
const cachedResponse = await caches.default.match(request);
if (cachedResponse) {
return mapResponse(cachedResponse);
}

const agent = HttpAgent.createSync({ host: env['API_GATEWAY'] });
const client = new HttpGatewayClient({
agent,
responseVerificationWasm: RESPONSE_VERIFICATION_WASM,
canisterId: env['CANISTER_ID'],
});

const response = await client.request({
request,
});

await caches.default.put(request, mapResponse(response.clone()));

return mapResponse(response);
},
} satisfies ExportedHandler<Env>;

function mapResponse(res: Response): Response {
return new Response(res.body, {
headers: res.headers,
status: res.status,
// This prevents Cloudflare from automatically encoding the response body
// according to the response's Content-Encoding header. Otherwise, the
// response body would be double-encoded.
//
// See: https://developers.cloudflare.com/workers/runtime-apis/response/#parameters
encodeBody: 'manual',
});
}
17 changes: 17 additions & 0 deletions examples/http-gateway/cloudflare/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"extends": "../../../tsconfig.json",
"compilerOptions": {
"target": "es2021",
"lib": ["es2021"],
"module": "es2022",
"moduleResolution": "Bundler",
"resolveJsonModule": true,
"allowJs": true,
"checkJs": false,
"noEmit": true,
"isolatedModules": true,
"allowSyntheticDefaultImports": true
},
"exclude": ["test"],
"include": ["worker-configuration.d.ts", "typings.d.ts", "src/**/*.ts"]
}
4 changes: 4 additions & 0 deletions examples/http-gateway/cloudflare/typings.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
declare module '@dfinity/response-verification/dist/web/web_bg.wasm' {
const value: Uint8Array;
export default value;
}
Loading