Skip to content

@stdlib/string/base/percent-encode produces malformed encoding and silently drops characters #15595

Open

Description

@barbierajput378-pixel

Description

percentEncode claims RFC 3986 conformance but has two related bugs, both caused by using a UTF-8 byte index to also index the original UTF-16 string.

Root cause

utf16ToUTF8Array returns an array of UTF-8 byte octets, so the loop variable i in lib/main.js counts bytes. But str.charAt(i) (used for unreserved characters) indexes UTF-16 code units. These only coincide for pure-ASCII strings — any multi-byte character before it throws off every subsequent index.

Related Issues

Related issues # , # , and # .

Questions

No.

Demo

No response

Reproduction

var percentEncode = require('@stdlib/string/base/percent-encode');

percentEncode('\t'); // Bug 1: missing zero-padding
percentEncode('\r'); // Bug 1: missing zero-padding
percentEncode('é1'); // Bug 2: character silently dropped

Expected Results

percentEncode('\t') → '%09'
percentEncode('\r') → '%0D'
percentEncode('é1') → '%C3%A91'

Actual Results

percentEncode('\t') → '%9'
percentEncode('\r') → '%D'
percentEncode('é1') → '%C3%A9'  (the '1' is dropped entirely)

Version

develop

Environments

Node.js

Browser Version

No response

Node.js / npm Version

v24.17.0

Platform

Windows

Checklist

  • Read and understood the Code of Conduct.
  • Searched for existing issues and pull requests.

Activity

  1. stdlib-bot commented on Sep 27, 2026

    @stdlib-bot
    Contributor

    👋 Hi there! 👋

    And thank you for opening your first issue! We will get back to you shortly. 🏃 💨

    If you have any further questions while waiting for a response, please join our Zulip community to chat with project maintainers and other community members.

  2. kgryte commented on Sep 28, 2026

    @kgryte
    Member

    @barbierajput378-pixel Thanks for reporting this issue. Do you have a proposed fix in mind?

  3. anbv29 commented on Sep 28, 2026

    @anbv29

    Hi maintainers — I’d like to contribute to “@stdlib/string/base/percent-encode produces malformed encoding and silently drops characters”. I have JavaScript/TypeScript experience and can take a focused approach: reproduce the report, trace the affected module, add a regression test for the stated behavior plus a nearby edge case, then implement the smallest compatible fix while keeping the public API and existing behavior stable. I’ll run the repository’s relevant test/lint/type-check commands and keep the PR limited to this issue. Would you be comfortable confirming this direction before I open a PR?

  4. barbierajput378-pixel commented on Sep 28, 2026

    @barbierajput378-pixel
    Author

    Thanks @kgryte Yes, the fix is small and confined to string/base/percent-encode/lib/main.js:

    1. Zero-pad octets < 0x10 so the output is always two hex digits (e.g. %09).
    2. For unreserved characters, emit String.fromCharCode( byte ) (every unreserved octet is ASCII) instead of str.charAt( i ), since i is a byte index into the UTF-8 array, not an index into the UTF-16 string.

    I'll add regression tests for \t, \r, é1, and a multi-byte character followed by an unreserved ASCII character, check whether the string/percent-encode wrapper needs any change, and open a PR shortly.

  5. kgryte commented on Sep 28, 2026

    @kgryte
    Member

    @anbv29 I suggest finding other "Good First Issues" to work on, and not this one.

  6. barbierajput378-pixel commented on Sep 28, 2026

    @barbierajput378-pixel
    Author

    For reference, I've opened #15620 with the fix I described above. It corrects both problems (zero-padding of octets < 0x10 and the byte-vs-UTF-16 index mismatch), adds regression tests for each, and I confirmed the string/percent-encode wrapper needs no changes. Happy to adjust whatever the reviewers prefer, @kgryte .

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    BugSomething isn't working.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions