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

Support range requests #28

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
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
10 changes: 0 additions & 10 deletions src/sw/controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,16 +107,6 @@ function meetsInterceptionPreconditions (event) {
return false
}

// range requests not supported yet.
const isStreamingMedia = ['video', 'audio'].includes(destination)
// HLS works fine, no range requests involved.
const isHLS = url.includes('.m3u8')

// TODO: Add check for range header, skip if present
if (isStreamingMedia && !isHLS) {
return false
}

// https://developer.mozilla.org/en-US/docs/Web/API/Request/mode
// "If a request is made to another origin with this mode set, the
// result is simply an error."
Expand Down
6 changes: 4 additions & 2 deletions src/sw/interceptor.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import toIterable from 'browser-readablestream-to-it'
import createDebug from 'debug'
import * as Sentry from '@sentry/browser'

import { getCidPathFromURL } from '../utils.js'
import { getCidPathFromURL, parseRange } from '../utils.js'

const debug = createDebug('sw')
const cl = console.log
Expand All @@ -14,6 +14,7 @@ export class Interceptor {
constructor(cid, saturn, clientId, event) {
this.cid = cid
this.cidPath = getCidPathFromURL(event.request.url, cid)
this.range = parseRange(event.request.headers.get('Range'))
this.saturn = saturn
this.clientId = clientId
this.event = event
Expand All @@ -36,7 +37,8 @@ export class Interceptor {
const opts = {
customerFallbackURL: self.event.request.url,
raceNodes: true,
firstHitDNS: true
firstHitDNS: true,
range: self.range
}
const contentItr = await self.saturn.fetchContentWithFallback(
self.cidPath,
Expand Down
40 changes: 40 additions & 0 deletions src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,43 @@ export function getCidPathFromURL(url, cid) {

return cidPath
}

export function parseRange(rangeHeader) {
if (typeof rangeHeader !== 'string') {
return
}

const index = rangeHeader.indexOf('=')

if (index === -1) {
return
}

// split the range string
const arr = rangeHeader.slice(index + 1).split(',')
// TODO: support multi-range requests
if (arr.length !== 1) {
return
}
const type = rangeHeader.slice(0, index)
if (type !== 'bytes') {
return
}

const range = arr[0].split('-')
const rangeStart = parseInt(range[0], 10)
const rangeEnd = parseInt(range[1], 10)

// -nnn
if (isNaN(rangeStart)) {
if (isNaN(rangeEnd)) {
return
}
return { rangeStart: -rangeEnd }
// nnn-
} else if (isNaN(rangeEnd)) {
return { rangeStart }
}

return { rangeStart, rangeEnd }
}
22 changes: 21 additions & 1 deletion test/utils.spec.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import assert from 'node:assert/strict'
import { describe, it } from 'node:test'
import { findCIDInURL, getCidPathFromURL } from '#src/utils.js'
import { findCIDInURL, getCidPathFromURL, parseRange } from '#src/utils.js'

describe('controller', () => {
it('should find cid in the subdomain', () => {
Expand Down Expand Up @@ -38,4 +38,24 @@ describe('controller', () => {
const foundCidPath = getCidPathFromURL(url, cid)
assert.strictEqual(foundCidPath, cidPath)
})

it('should parse ranges', () => {
assert.strictEqual(parseRange(undefined), undefined)
assert.strictEqual(parseRange(null), undefined)
assert.strictEqual(parseRange(''), undefined)
assert.strictEqual(parseRange('apples=0-1000'), undefined)
assert.strictEqual(parseRange('bytes=0-1000,2000-3000'), undefined)
assert.strictEqual(parseRange('bytes=cheese-crackers'), undefined)
assert.strictEqual(parseRange('bytes=cheese'), undefined)
assert.deepEqual(parseRange('bytes=0-1000'), {
rangeStart: 0,
rangeEnd: 1000
})
assert.deepEqual(parseRange('bytes=1000'), {
rangeStart: 1000
})
assert.deepEqual(parseRange('bytes=-1000'), {
rangeStart: -1000
})
})
})
Loading