'use strict' const { inspect } = require('node:util') const { test } = require('node:test') const parseParams = require('../lib/utils/parseParams') test('parse-params', async t => { const tests = [ { source: 'video/ogg', expected: ['video/ogg'], what: 'No parameters' }, { source: 'video/ogg;', expected: ['video/ogg'], what: 'No parameters (with separator)' }, { source: 'video/ogg; ', expected: ['video/ogg'], what: 'No parameters (with separator followed by whitespace)' }, { source: ';video/ogg', expected: ['', 'video/ogg'], what: 'Empty parameter' }, { source: 'video/*', expected: ['video/*'], what: 'Subtype with asterisk' }, { source: 'text/plain; encoding=utf8', expected: ['text/plain', ['encoding', 'utf8']], what: 'Unquoted' }, { source: 'text/plain; encoding=', expected: ['text/plain', ['encoding', '']], what: 'Unquoted empty string' }, { source: 'text/plain; encoding="utf8"', expected: ['text/plain', ['encoding', 'utf8']], what: 'Quoted' }, { source: 'text/plain; greeting="hello \\"world\\""', expected: ['text/plain', ['greeting', 'hello "world"']], what: 'Quotes within quoted' }, { source: 'text/plain; greeting="hello \\\\world\\\\"', expected: ['text/plain', ['greeting', 'hello \\world\\']], what: 'Escape within quoted' }, { source: 'text/plain; encoding=""', expected: ['text/plain', ['encoding', '']], what: 'Quoted empty string' }, { source: 'text/plain; encoding="utf8";\t foo=bar;test', expected: ['text/plain', ['encoding', 'utf8'], ['foo', 'bar'], 'test'], what: 'Multiple params with various spacing' }, { source: "text/plain; filename*=iso-8859-1'en'%A3%20rates", expected: ['text/plain', ['filename', '£ rates']], what: 'Extended parameter (RFC 5987) with language' }, { source: "text/plain; filename*=utf-8''%c2%a3%20and%20%e2%82%ac%20rates", expected: ['text/plain', ['filename', '£ and € rates']], what: 'Extended parameter (RFC 5987) without language' }, { source: "text/plain; filename*=utf-8''%E6%B5%8B%E8%AF%95%E6%96%87%E6%A1%A3", expected: ['text/plain', ['filename', '测试文档']], what: 'Extended parameter (RFC 5987) without language #2' }, { source: "text/plain; filename*=iso-8859-1'en'%A3%20rates; altfilename*=utf-8''%c2%a3%20and%20%e2%82%ac%20rates", expected: ['text/plain', ['filename', '£ rates'], ['altfilename', '£ and € rates']], what: 'Multiple extended parameters (RFC 5987) with mixed charsets' }, { source: "text/plain; filename*=iso-8859-1'en'%A3%20rates; altfilename=\"foobarbaz\"", expected: ['text/plain', ['filename', '£ rates'], ['altfilename', 'foobarbaz']], what: 'Mixed regular and extended parameters (RFC 5987)' }, { source: "text/plain; filename*=iso-8859-1'en';", expected: ['text/plain', ['filename', '']], what: 'Mixed regular and extended parameters (RFC 5987) with separator' }, { source: "text/plain; filename=\"foobarbaz\"; altfilename*=iso-8859-1'en'%A3%20rates", expected: ['text/plain', ['filename', 'foobarbaz'], ['altfilename', '£ rates']], what: 'Mixed regular and extended parameters (RFC 5987) #2' }, { source: 'text/plain; filename="C:\\folder\\test.png"', expected: ['text/plain', ['filename', 'C:\\folder\\test.png']], what: 'Unescaped backslashes should be considered backslashes' }, { source: 'text/plain; filename="John \\"Magic\\" Smith.png"', expected: ['text/plain', ['filename', 'John "Magic" Smith.png']], what: 'Escaped double-quotes should be considered double-quotes' }, { source: 'multipart/form-data; charset=utf-8; boundary=0xKhTmLbOuNdArY', expected: ['multipart/form-data', ['charset', 'utf-8'], ['boundary', '0xKhTmLbOuNdArY']], what: 'Multiple non-quoted parameters' }, { source: 'form-data; name="file"; filename="payload.jpg".html', expected: ['form-data', ['name', 'file'], ['filename', 'payload.jpg']], what: 'Improperly quoted filename should stop at closing quote (RFC 2183/7578 compliance)' }, { source: 'form-data; name="field"; filename="test.pdf"extra.txt', expected: ['form-data', ['name', 'field'], ['filename', 'test.pdf']], what: 'Quoted filename with trailing unquoted text should stop at closing quote' }, { source: 'text/plain; charset="utf-8"garbage; boundary=test', expected: ['text/plain', ['charset', 'utf-8'], ['boundary', 'test']], what: 'Quoted parameter with trailing garbage should stop at closing quote' }, { source: 'form-data; name="héllo"', expected: ['form-data', ['name', 'h�llo']], what: 'Non-ASCII name in fast path' }, { source: 'form-data; name="hello"; filename="café.png"', expected: ['form-data', ['name', 'hello'], ['filename', 'caf�.png']], what: 'Non-ASCII filename in fast path' }, { source: 'form-data; name="hello";filename="world.png"', expected: ['form-data', ['name', 'hello'], ['filename', 'world.png']], what: 'No whitespace between name and filename' }, { source: 'form-data; name="hello" ; filename="world.png"', expected: ['form-data', ['name', 'hello'], ['filename', 'world.png']], what: 'Whitespace between name and filename' }, { source: 'form-data; name="hello"; filename="back\\slash.png"', expected: ['form-data', ['name', 'hello'], ['filename', 'back\\slash.png']], what: 'Filename with backslash falls back to slow parser' }, { source: 'form-data; name="hello"; extra=stuff', expected: ['form-data', ['name', 'hello'], ['extra', 'stuff']], what: 'Fast path falls back when filename is missing' }, { source: 'form-data; name="hello"; filename="unterminated', expected: ['form-data', ['name', 'hello'], ['filename', 'unterminated']], what: 'Fast path falls back when filename is unterminated' } ] t.plan(tests.length) for (const v of tests) { await t.test(v.what, t => { t.plan(1) const result = parseParams(v.source) t.assert.deepStrictEqual( result, v.expected, `parsed parameters match.\nSaw: ${inspect(result)}\nExpected: ${inspect(v.expected)}`) }) } })