Skip to content

Commit

Permalink
remove third party blob support (#2727)
Browse files Browse the repository at this point in the history
  • Loading branch information
KhafraDev authored Jul 3, 2024
1 parent 8a940ec commit 4ba1d13
Show file tree
Hide file tree
Showing 7 changed files with 14 additions and 203 deletions.
110 changes: 2 additions & 108 deletions lib/web/fetch/file.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,107 +93,6 @@ class File extends Blob {
}
}

class FileLike {
constructor (blobLike, fileName, options = {}) {
// TODO: argument idl type check

// The File constructor is invoked with two or three parameters, depending
// on whether the optional dictionary parameter is used. When the File()
// constructor is invoked, user agents must run the following steps:

// 1. Let bytes be the result of processing blob parts given fileBits and
// options.

// 2. Let n be the fileName argument to the constructor.
const n = fileName

// 3. Process FilePropertyBag dictionary argument by running the following
// substeps:

// 1. If the type member is provided and is not the empty string, let t
// be set to the type dictionary member. If t contains any characters
// outside the range U+0020 to U+007E, then set t to the empty string
// and return from these substeps.
// TODO
const t = options.type

// 2. Convert every character in t to ASCII lowercase.
// TODO

// 3. If the lastModified member is provided, let d be set to the
// lastModified dictionary member. If it is not provided, set d to the
// current date and time represented as the number of milliseconds since
// the Unix Epoch (which is the equivalent of Date.now() [ECMA-262]).
const d = options.lastModified ?? Date.now()

// 4. Return a new File object F such that:
// F refers to the bytes byte sequence.
// F.size is set to the number of total bytes in bytes.
// F.name is set to n.
// F.type is set to t.
// F.lastModified is set to d.

this[kState] = {
blobLike,
name: n,
type: t,
lastModified: d
}
}

stream (...args) {
webidl.brandCheck(this, FileLike)

return this[kState].blobLike.stream(...args)
}

arrayBuffer (...args) {
webidl.brandCheck(this, FileLike)

return this[kState].blobLike.arrayBuffer(...args)
}

slice (...args) {
webidl.brandCheck(this, FileLike)

return this[kState].blobLike.slice(...args)
}

text (...args) {
webidl.brandCheck(this, FileLike)

return this[kState].blobLike.text(...args)
}

get size () {
webidl.brandCheck(this, FileLike)

return this[kState].blobLike.size
}

get type () {
webidl.brandCheck(this, FileLike)

return this[kState].blobLike.type
}

get name () {
webidl.brandCheck(this, FileLike)

return this[kState].name
}

get lastModified () {
webidl.brandCheck(this, FileLike)

return this[kState].lastModified
}

get [Symbol.toStringTag] () {
return 'File'
}
}

Object.defineProperties(File.prototype, {
[Symbol.toStringTag]: {
value: 'File',
Expand Down Expand Up @@ -326,13 +225,8 @@ function convertLineEndingsNative (s) {
function isFileLike (object) {
return (
(NativeFile && object instanceof NativeFile) ||
object instanceof File || (
object &&
(typeof object.stream === 'function' ||
typeof object.arrayBuffer === 'function') &&
object[Symbol.toStringTag] === 'File'
)
object instanceof File // undici File
)
}

module.exports = { File, FileLike, isFileLike }
module.exports = { File, isFileLike }
10 changes: 3 additions & 7 deletions lib/web/fetch/formdata.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
const { isBlobLike, iteratorMixin } = require('./util')
const { kState } = require('./symbols')
const { kEnumerableProperty } = require('../../core/util')
const { File: UndiciFile, FileLike, isFileLike } = require('./file')
const { File: UndiciFile, isFileLike } = require('./file')
const { webidl } = require('./webidl')
const { File: NativeFile } = require('node:buffer')

Expand Down Expand Up @@ -192,9 +192,7 @@ function makeEntry (name, value, filename) {
// 1. If value is not a File object, then set value to a new File object,
// representing the same bytes, whose name attribute value is "blob"
if (!isFileLike(value)) {
value = value instanceof Blob
? new File([value], 'blob', { type: value.type })
: new FileLike(value, 'blob', { type: value.type })
value = new File([value], 'blob', { type: value.type })
}

// 2. If filename is given, then set value to a new File object,
Expand All @@ -206,9 +204,7 @@ function makeEntry (name, value, filename) {
lastModified: value.lastModified
}

value = (NativeFile && value instanceof NativeFile) || value instanceof UndiciFile
? new File([value], filename, options)
: new FileLike(value, filename, options)
value = new File([value], filename, options)
}
}

Expand Down
36 changes: 3 additions & 33 deletions test/fetch/file.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ const { Blob } = require('node:buffer')
const { test } = require('node:test')
const assert = require('node:assert')
const { tspl } = require('@matteo.collina/tspl')
const { File, FileLike } = require('../../lib/web/fetch/file')
const { File } = require('../../lib/web/fetch/file')

test('args validation', (t) => {
const { throws, doesNotThrow, strictEqual } = tspl(t, { plan: 14 })
const { throws, doesNotThrow, strictEqual } = tspl(t, { plan: 4 })

throws(() => {
File.prototype.name.toString()
Expand All @@ -19,36 +19,7 @@ test('args validation', (t) => {
File.prototype[Symbol.toStringTag].charAt(0)
}, TypeError)

throws(() => {
FileLike.prototype.stream.call(null)
}, TypeError)
throws(() => {
FileLike.prototype.arrayBuffer.call(null)
}, TypeError)
throws(() => {
FileLike.prototype.slice.call(null)
}, TypeError)
throws(() => {
FileLike.prototype.text.call(null)
}, TypeError)
throws(() => {
FileLike.prototype.size.toString()
}, TypeError)
throws(() => {
FileLike.prototype.type.toString()
}, TypeError)
throws(() => {
FileLike.prototype.name.toString()
}, TypeError)
throws(() => {
FileLike.prototype.lastModified.toString()
}, TypeError)
doesNotThrow(() => {
FileLike.prototype[Symbol.toStringTag].charAt(0)
}, TypeError)

strictEqual(File.prototype[Symbol.toStringTag], 'File')
strictEqual(FileLike.prototype[Symbol.toStringTag], 'File')
})

test('return value of File.lastModified', (t) => {
Expand All @@ -61,9 +32,8 @@ test('return value of File.lastModified', (t) => {
})

test('Symbol.toStringTag', (t) => {
const { strictEqual } = tspl(t, { plan: 2 })
const { strictEqual } = tspl(t, { plan: 1 })
strictEqual(new File([], '')[Symbol.toStringTag], 'File')
strictEqual(new FileLike()[Symbol.toStringTag], 'File')
})

test('arguments', () => {
Expand Down
12 changes: 0 additions & 12 deletions test/fetch/formdata.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ const { test } = require('node:test')
const assert = require('node:assert')
const { tspl } = require('@matteo.collina/tspl')
const { FormData, File, Response } = require('../../')
const { Blob: ThirdPartyBlob } = require('formdata-node')
const { Blob } = require('node:buffer')
const { isFormDataLike } = require('../../lib/core/util')
const ThirdPartyFormDataInvalid = require('form-data')
Expand Down Expand Up @@ -110,17 +109,6 @@ test('append blob', async () => {
assert.strictEqual(form.get('asd'), null)
})

test('append third-party blob', async () => {
const form = new FormData()
form.set('asd', new ThirdPartyBlob(['asd1'], { type: 'text/plain' }))

assert.strictEqual(form.has('asd'), true)
assert.strictEqual(form.get('asd').type, 'text/plain')
assert.strictEqual(await form.get('asd').text(), 'asd1')
form.delete('asd')
assert.strictEqual(form.get('asd'), null)
})

test('append string', () => {
const form = new FormData()
form.set('k1', 'v1')
Expand Down
9 changes: 0 additions & 9 deletions test/fetch/request.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ const {
} = require('../../')
const { fromInnerRequest, makeRequest } = require('../../lib/web/fetch/request')
const {
Blob: ThirdPartyBlob,
FormData: ThirdPartyFormData
} = require('formdata-node')
const { kState, kGuard, kRealm, kSignal, kHeaders } = require('../../lib/web/fetch/symbols')
Expand Down Expand Up @@ -419,14 +418,6 @@ test('RequestInit.signal option', async () => {
}), TypeError)
})

test('constructing Request with third party Blob body', async () => {
const blob = new ThirdPartyBlob(['text'])
const req = new Request('http://asd', {
method: 'POST',
body: blob
})
assert.strictEqual(await req.text(), 'text')
})
test('constructing Request with third party FormData body', async () => {
const form = new ThirdPartyFormData()
form.set('key', 'value')
Expand Down
6 changes: 0 additions & 6 deletions test/fetch/response.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ const {
} = require('../../')
const { fromInnerResponse, makeResponse } = require('../../lib/web/fetch/response')
const {
Blob: ThirdPartyBlob,
FormData: ThirdPartyFormData
} = require('formdata-node')
const { kState, kGuard, kRealm, kHeaders } = require('../../lib/web/fetch/symbols')
Expand Down Expand Up @@ -222,11 +221,6 @@ test('constructing a Response with a ReadableStream body', async (t) => {
})
})

test('constructing Response with third party Blob body', async () => {
const blob = new ThirdPartyBlob(['text'])
const res = new Response(blob)
assert.strictEqual(await res.text(), 'text')
})
test('constructing Response with third party FormData body', async () => {
const form = new ThirdPartyFormData()
form.set('key', 'value')
Expand Down
34 changes: 6 additions & 28 deletions test/issue-2065.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ const { tspl } = require('@matteo.collina/tspl')
const { test, after } = require('node:test')
const { createServer } = require('node:http')
const { once } = require('node:events')
const { createReadStream } = require('node:fs')
const { openAsBlob } = require('node:fs')
const { File, FormData, request } = require('..')

test('undici.request with a FormData body should set content-length header', async (t) => {
Expand All @@ -27,41 +27,19 @@ test('undici.request with a FormData body should set content-length header', asy
})
})

test('undici.request with a FormData stream value should set transfer-encoding header', async (t) => {
t = tspl(t, { plan: 1 })
test('undici.request with a FormData stream value should set transfer-encoding header', { skip: !openAsBlob }, async (t) => {
const { ok } = tspl(t, { plan: 1 })

const server = createServer((req, res) => {
t.strictEqual(req.headers['transfer-encoding'], 'chunked')
ok(req.headers['content-type'].startsWith('multipart/form-data'))
res.end()
}).listen(0)

after(() => server.close())
t.after(server.close.bind(server))
await once(server, 'listening')

class BlobFromStream {
#stream
#type
constructor (stream, type) {
this.#stream = stream
this.#type = type
}

stream () {
return this.#stream
}

get type () {
return this.#type
}

get [Symbol.toStringTag] () {
return 'Blob'
}
}

const body = new FormData()
const fileReadable = createReadStream(__filename)
body.set('file', new BlobFromStream(fileReadable, '.js'), 'streamfile')
body.set('file', await openAsBlob(__filename), 'streamfile')

await request(`http://localhost:${server.address().port}`, {
method: 'POST',
Expand Down

0 comments on commit 4ba1d13

Please sign in to comment.