-
Notifications
You must be signed in to change notification settings - Fork 106
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: verified-fetch etag header (#434)
Fixes the formatting for the etag header --------- Co-authored-by: Marcin Rataj <lidel@lidel.org> Co-authored-by: Alex Potsides <alex@achingbrain.net>
- Loading branch information
1 parent
754c7af
commit 8db7792
Showing
5 changed files
with
81 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export type RequestFormatShorthand = 'raw' | 'car' | 'tar' | 'ipns-record' | 'dag-json' | 'dag-cbor' | 'json' | 'cbor' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import type { RequestFormatShorthand } from '../types.js' | ||
import type { CID } from 'multiformats/cid' | ||
|
||
interface GetETagArg { | ||
cid: CID | ||
reqFormat?: RequestFormatShorthand | ||
rangeStart?: number | ||
rangeEnd?: number | ||
/** | ||
* Weak Etag is used when we can't guarantee byte-for-byte-determinism (generated, or mutable content). | ||
* Some examples: | ||
* - IPNS requests | ||
* - CAR streamed with blocks in non-deterministic order | ||
* - TAR streamed with files in non-deterministic order | ||
*/ | ||
weak?: boolean | ||
} | ||
|
||
/** | ||
* etag | ||
* you need to wrap cid with "" | ||
* we use strong Etags for immutable responses and weak one (prefixed with W/ ) for mutable/generated ones (ipns and generated HTML). | ||
* block and car responses should have different etag than deserialized one, so you can add some prefix like we do in existing gateway | ||
* | ||
* @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag | ||
* @see https://specs.ipfs.tech/http-gateways/path-gateway/#etag-response-header | ||
*/ | ||
export function getETag ({ cid, reqFormat, weak, rangeStart, rangeEnd }: GetETagArg): string { | ||
const prefix = weak === true ? 'W/' : '' | ||
let suffix = reqFormat == null ? '' : `.${reqFormat}` | ||
if (rangeStart != null || rangeEnd != null) { | ||
suffix += `.${rangeStart ?? '0'}-${rangeEnd ?? 'N'}` | ||
} | ||
|
||
return `${prefix}"${cid.toString()}${suffix}"` | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import { expect } from 'aegir/chai' | ||
import { CID } from 'multiformats/cid' | ||
import { getETag } from '../src/utils/get-e-tag.js' | ||
|
||
const cidString = 'QmQJ8fxavY54CUsxMSx9aE9Rdcmvhx8awJK2jzJp4iAqCr' | ||
const testCID = CID.parse(cidString) | ||
|
||
describe('getETag', () => { | ||
it('CID eTag', () => { | ||
expect(getETag({ cid: testCID, weak: true })).to.equal(`W/"${cidString}"`) | ||
expect(getETag({ cid: testCID, weak: false })).to.equal(`"${cidString}"`) | ||
}) | ||
|
||
it('should return ETag with CID and format suffix', () => { | ||
expect(getETag({ cid: testCID, reqFormat: 'raw' })).to.equal(`"${cidString}.raw"`) | ||
expect(getETag({ cid: testCID, reqFormat: 'json' })).to.equal(`"${cidString}.json"`) | ||
}) | ||
|
||
it('should return ETag with CID and range suffix', () => { | ||
expect(getETag({ cid: testCID, weak: true, reqFormat: 'car', rangeStart: 10, rangeEnd: 20 })).to.equal(`W/"${cidString}.car.10-20"`) | ||
expect(getETag({ cid: testCID, weak: false, reqFormat: 'car', rangeStart: 10, rangeEnd: 20 })).to.equal(`"${cidString}.car.10-20"`) | ||
}) | ||
|
||
it('should return ETag with CID, format and range suffix', () => { | ||
expect(getETag({ cid: testCID, reqFormat: 'raw', weak: false, rangeStart: 10, rangeEnd: 20 })).to.equal(`"${cidString}.raw.10-20"`) | ||
}) | ||
|
||
it('should handle undefined rangeStart and rangeEnd', () => { | ||
expect(getETag({ cid: testCID, reqFormat: 'raw', weak: false, rangeStart: undefined, rangeEnd: undefined })).to.equal(`"${cidString}.raw"`) | ||
expect(getETag({ cid: testCID, reqFormat: 'raw', weak: false, rangeStart: 55, rangeEnd: undefined })).to.equal(`"${cidString}.raw.55-N"`) | ||
expect(getETag({ cid: testCID, reqFormat: 'raw', weak: false, rangeStart: undefined, rangeEnd: 77 })).to.equal(`"${cidString}.raw.0-77"`) | ||
}) | ||
}) |