Skip to content

Incorrect parsing of nested params with closing square bracket ] in property name #493

@gronke

Description

@gronke

Search parameters with closing square bracket in nested property names are parsed incorrectly.

Here demonstrated with /?search[withbracket[]]=foobar:

> var qs = require("qs");
undefined
> input = { search: { "withbracket[]": "foobar" }}
{ search: { 'withbracket[]': 'foobar' } }
> output = qs.stringify(input, { encode: false })
'search[withbracket[]]=foobar'
> result = qs.parse(output)
{ 'search[withbracket': [ 'foobar' ] }
> assert.deepEqual(input, result)
Uncaught AssertionError [ERR_ASSERTION]: Expected values to be loosely deep-equal:

{
  search: {
    'withbracket[]': 'foobar'
  }
}

should loosely deep-equal

{
  'search[withbracket': [
    'foobar'
  ]
}
    at REPL280:1:8
    at Script.runInThisContext (node:vm:129:12)
    at REPLServer.defaultEval (node:repl:572:29)
    at bound (node:domain:433:15)
    at REPLServer.runBound [as eval] (node:domain:444:12)
    at REPLServer.onLine (node:repl:902:10)
    at REPLServer.emit (node:events:525:35)
    at REPLServer.emit (node:domain:489:12)
    at [_onLine] [as _onLine] (node:internal/readline/interface:425:12)
    at [_line] [as _line] (node:internal/readline/interface:886:18) {
  generatedMessage: true,
  code: 'ERR_ASSERTION',
  actual: [Object],
  expected: [Object],
  operator: 'deepEqual'
}

For comparison the result with the native URL object:

> url = new URL("http://example.com/?search[withbracket[]]=foobar")
URL {
  href: 'http://example.com/?search[withbracket[]]=foobar',
  origin: 'http://example.com',
  protocol: 'http:',
  username: '',
  password: '',
  host: 'example.com',
  hostname: 'example.com',
  port: '',
  pathname: '/',
  search: '?search[withbracket[]]=foobar',
  searchParams: URLSearchParams { 'search[withbracket[]]' => 'foobar' },
  hash: ''
}
> [...url.searchParams.keys()]
[ 'search[withbracket[]]' ]

When parsing a query without braces, the result looks like:

> qs.parse("search[okay]=baz")
{ search: { okay: 'baz' } }

So it should be a nested object.

Current Result

{ "search[withbracket": ["foobar"] }

Expected Result

{ "search": { "withbracket[]": ["foobar"] }}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions