Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Encoding URLs with %26 or %2C parameters produce errors #279

@alexander-nikiforov-intentive

Description

Environment

Node --version -> 22.19.0
npm -version -> 10.9.3

package.json

Reproduction

Here are the package.json and server.js to reproduce the error:

It is a simple express hello-world application. If one starts it via node server.js and opens browser in http://localhost:3000 then in console.log at Node server one can see the modifiers object is wrong.

It has only w property with wrong value 75&q=10

Describe the bug

Hi everyone,

If we use %26 or %2C URLs in IPX Module, then we parameters are not processed properly.

  • /w_75%26f_webp/example.jpg - processes path as one parameter: w=75&f_webp -> wrong
  • /w_75&f_webp/example.jpg - processes path with two parameters w=75 and f=webp -> correct

According to URL specification both of the paths should actually give the same result since & and , are reserved characters.

Here is the simple express application that takes a code from server.ts (https://github.com/unjs/ipx/blob/main/src/server.ts#L35 to https://github.com/unjs/ipx/blob/main/src/server.ts#L62) and confirms the error:

const express = require('express');
const { decode } = require("ufo");

// Next initialize the application
const app = express();

function safeString(input) {
  return JSON.stringify(input)
    .replace(/^"|"$/g, "")
    .replace(/\\+/g, "\\")
    .replace(/\\"/g, '"');
}

// routing path
app.get('/', (req, res) => {

  let url = '/w_75%26q_10/example.jpg';
  const [modifiersString = "", ...idSegments] = url
    .slice(1 /* leading slash */)
    .split("/");

  const MODIFIER_SEP = /[&,]/g;
  const MODIFIER_VAL_SEP = /[:=_]/;

  const modifiers = Object.create(null);

  // Read modifiers from first segment
  if (modifiersString !== "_") {

    // correct version -> replaces %26 with & so that MODIFIER_SEP can properly separate parameters
    // for (const p of modifiersString.replace(/%26/gi, "&").split(MODIFIER_SEP)) {

    // wrong: does no account for %26
    // https://github.com/unjs/ipx/blob/main/src/server.ts#L62
    for (const p of modifiersString.split(MODIFIER_SEP)) {
      const [key, ...values] = p.split(MODIFIER_VAL_SEP);
      modifiers[safeString(key)] = values
        .map((v) => safeString(decode(v)))
        .join("_");
    }
  }

  console.log(modifiers);

});

// Start the server
app.listen(3000, () => {
  console.log('Server started on port 3000');
});

One possible solution would e.g. be a hard-replace separators at the line: https://github.com/unjs/ipx/blob/main/src/server.ts#L62 but may be you have better ideas or other considerations:

for (const p of modifiersString.replace(/%26/gi, "&").split(MODIFIER_SEP)) { 
    ...
}

Could you confirm the bug, or do you need any additional information?

Additional context

No response

Logs

Server started on port 3000 -> server.js:49
{w: '75&q_10'} -> server.js:43

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions