Skip to content

fix(backend): use empty separator when joining HTTP body chunks (ACM-38039)#6528

Merged
KevinFCormier merged 1 commit into
mainfrom
fix/ACM-38039-chunk-join-separator
Jul 21, 2026
Merged

fix(backend): use empty separator when joining HTTP body chunks (ACM-38039)#6528
KevinFCormier merged 1 commit into
mainfrom
fix/ACM-38039-chunk-join-separator

Conversation

@KevinFCormier

@KevinFCormier KevinFCormier commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

📝 Summary

Ticket Summary (Title):
Backend: HTTP request body chunks joined without empty separator can corrupt JSON payloads

Ticket Link:
https://issues.redhat.com/browse/ACM-38039

Type of Change:

  • 🐞 Bug Fix
  • ✨ Feature
  • 🔧 Refactor
  • 💸 Tech Debt
  • 🧪 Test-related
  • 📄 Docs

Root Cause

Several backend route handlers collect HTTP request body data using req.on('data') listeners that push chunks into an array, then join them before JSON.parse(). However, Array.join() was called without an explicit empty-string separator, which means JavaScript's default comma (,) separator would be used. If a request body arrives in multiple TCP chunks, the commas inserted at chunk boundaries corrupt the JSON before parsing.

One location (virtualMachineProxy.ts) already used the correct .join('') form — this PR aligns all other locations.

Changes

Changed .join() to .join('') in 9 locations across 8 backend files:

File Function
backend/src/routes/rosaWizardApi.ts getAwsAccountIds, getAwsBillingAccountIds
backend/src/routes/userpreference.ts userpreference
backend/src/routes/operatorCheck.ts operatorCheck
backend/src/routes/aggregators/statuses.ts requestAggregatedStatuses
backend/src/routes/aggregators/appSetData.ts requestAggregatedAppSetData
backend/src/routes/ansibletower.ts ansibleTower
backend/src/lib/pagination.ts requestListView
backend/src/routes/upgrade-risks-prediction.ts upgradeRisksPrediction

Added a requestMultiChunk() test helper and a regression test that sends a request body split across two chunks to verify correct reassembly.

Context

Discovered during review of PR #6490. See this comment thread.


✅ Checklist

General

  • PR title follows the convention
  • Code builds and runs locally without errors
  • No console logs, commented-out code, or unnecessary files
  • All commits are meaningful and well-labeled
  • All new display strings are externalized for localization (English only) — N/A, no new strings

If Bugfix

  • Root cause and fix summary are documented in the ticket (for future reference / errata)
  • Fix tested thoroughly and resolves the issue
  • Test(s) added to prevent regression

🗒️ Notes for Reviewers

  • The fix is mechanical: .join().join('') across all HTTP body chunk reassembly sites.
  • Locations in utils.ts and applicationsOCP.ts that use .join() for cache key construction are intentionally comma-separated and were not changed.
  • In practice this bug was likely never hit because request bodies for these endpoints are small enough to arrive in a single chunk, but it is a latent correctness issue.

Summary by CodeRabbit

  • Bug Fixes

    • Fixed request handling for JSON payloads received in multiple network chunks.
    • Prevented malformed JSON parsing across pagination, aggregation, operator checks, user preferences, account lookup, and upgrade risk prediction endpoints.
    • Improved reliability for requests whose bodies are split during transmission.
  • Tests

    • Added coverage verifying successful processing of multi-chunk requests.

…38039)

Signed-off-by: Kevin Cormier <kcormier@redhat.com>
@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Request handlers now join streamed request-body chunks with an empty separator before JSON parsing or forwarding. Test utilities add two-chunk HTTP/2 requests, and the operator-check suite verifies the resulting behavior.

Changes

Request body chunking

Layer / File(s) Summary
Body reconstruction across handlers
backend/src/lib/pagination.ts, backend/src/routes/aggregators/*, backend/src/routes/ansibletower.ts, backend/src/routes/operatorCheck.ts, backend/src/routes/rosaWizardApi.ts, backend/src/routes/upgrade-risks-prediction.ts, backend/src/routes/userpreference.ts
Request payload chunks are concatenated with join('') instead of the default comma separator.
Multi-chunk request test support
backend/test/mock-request.ts, backend/test/routes/operatorCheck.test.ts
Adds a helper that writes JSON in two chunks and verifies successful multi-chunk parsing by /operatorCheck.

Estimated code review effort: 2 (Simple) | ~10 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly states the backend chunk-joining fix and matches the main change set.
Description check ✅ Passed The description matches the template with summary, ticket link, change type, checklist, and reviewer notes.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/ACM-38039-chunk-join-separator

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install timed out. The project may have too many dependencies for the sandbox.


Comment @coderabbitai help to get the list of available commands.

@KevinFCormier

Copy link
Copy Markdown
Contributor Author

FYI @davidaznaur @vishsanghishetty

@davidaznaur davidaznaur left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thank you for updating wizard ones as well

@vishsanghishetty vishsanghishetty left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm!

@openshift-ci

openshift-ci Bot commented Jul 21, 2026

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: davidaznaur, KevinFCormier, vishsanghishetty

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:
  • OWNERS [KevinFCormier,vishsanghishetty]

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
backend/test/routes/operatorCheck.test.ts (1)

64-79: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add a non-ASCII chunk-boundary regression.

This test validates comma-free assembly, but its ASCII-only operator payload cannot detect UTF-8 corruption when a character spans chunks. Add a valid Unicode-bearing request case for one updated handler, or cover the shared body parser directly.

As per coding guidelines, tests should meaningfully cover behavior, not just achieve coverage metrics.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/test/routes/operatorCheck.test.ts` around lines 64 - 79, Add a
regression case near the existing requestMultiChunk test that sends a valid
operator payload containing a non-ASCII character split across UTF-8 byte
chunks, then assert the handler preserves the decoded value and returns the
expected response. Reuse requestMultiChunk and the existing operator-check
assertions, or test the shared body parser directly if that is the applicable
boundary.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@backend/src/lib/pagination.ts`:
- Line 67: Update each request-body collector to decode UTF-8 safely before JSON
parsing, avoiding string concatenation of raw chunks that can corrupt split
multibyte characters. Apply the same change at backend/src/lib/pagination.ts:67,
backend/src/routes/aggregators/appSetData.ts:36,
backend/src/routes/aggregators/statuses.ts:36,
backend/src/routes/ansibletower.ts:39, backend/src/routes/operatorCheck.ts:44,
backend/src/routes/rosaWizardApi.ts:40, backend/src/routes/rosaWizardApi.ts:76,
backend/src/routes/upgrade-risks-prediction.ts:49, and
backend/src/routes/userpreference.ts:83 by setting UTF-8 encoding on the request
stream or buffering chunks and decoding once with UTF-8 before
concatenation/JSON.parse.

---

Nitpick comments:
In `@backend/test/routes/operatorCheck.test.ts`:
- Around line 64-79: Add a regression case near the existing requestMultiChunk
test that sends a valid operator payload containing a non-ASCII character split
across UTF-8 byte chunks, then assert the handler preserves the decoded value
and returns the expected response. Reuse requestMultiChunk and the existing
operator-check assertions, or test the shared body parser directly if that is
the applicable boundary.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: e23fecec-27d2-43cb-a66c-2a541eb10dbe

📥 Commits

Reviewing files that changed from the base of the PR and between 819efd7 and 5771344.

📒 Files selected for processing (10)
  • backend/src/lib/pagination.ts
  • backend/src/routes/aggregators/appSetData.ts
  • backend/src/routes/aggregators/statuses.ts
  • backend/src/routes/ansibletower.ts
  • backend/src/routes/operatorCheck.ts
  • backend/src/routes/rosaWizardApi.ts
  • backend/src/routes/upgrade-risks-prediction.ts
  • backend/src/routes/userpreference.ts
  • backend/test/mock-request.ts
  • backend/test/routes/operatorCheck.test.ts

})
req.on('end', async () => {
const body = chucks.join()
const body = chucks.join('')

@coderabbitai coderabbitai Bot Jul 21, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
files=(
  backend/src/lib/pagination.ts
  backend/src/routes/aggregators/appSetData.ts
  backend/src/routes/aggregators/statuses.ts
  backend/src/routes/ansibletower.ts
  backend/src/routes/operatorCheck.ts
  backend/src/routes/rosaWizardApi.ts
  backend/src/routes/upgrade-risks-prediction.ts
  backend/src/routes/userpreference.ts
)

for file in "${files[@]}"; do
  echo "== $file =="
  rg -n "setEncoding|join\\(['\"][\"']\\)" "$file" || true
done

Repository: stolostron/console

Length of output: 843


🏁 Script executed:

#!/bin/bash
set -euo pipefail

files=(
  backend/src/lib/pagination.ts
  backend/src/routes/aggregators/appSetData.ts
  backend/src/routes/aggregators/statuses.ts
  backend/src/routes/ansibletower.ts
  backend/src/routes/operatorCheck.ts
  backend/src/routes/rosaWizardApi.ts
  backend/src/routes/upgrade-risks-prediction.ts
  backend/src/routes/userpreference.ts
)

for file in "${files[@]}"; do
  echo "===== $file ====="
  wc -l "$file"
  sed -n '1,140p' "$file" | nl -ba | sed -n '1,140p'
  echo
done

Repository: stolostron/console

Length of output: 273


🏁 Script executed:

#!/bin/bash
set -euo pipefail

files=(
  backend/src/lib/pagination.ts
  backend/src/routes/aggregators/appSetData.ts
  backend/src/routes/aggregators/statuses.ts
  backend/src/routes/ansibletower.ts
  backend/src/routes/operatorCheck.ts
  backend/src/routes/rosaWizardApi.ts
  backend/src/routes/upgrade-risks-prediction.ts
  backend/src/routes/userpreference.ts
)

for file in "${files[@]}"; do
  echo "===== $file ====="
  sed -n '1,160p' "$file" | cat -n
  echo
done

Repository: stolostron/console

Length of output: 39148


🏁 Script executed:

#!/bin/bash
set -euo pipefail

files=(
  backend/src/lib/pagination.ts
  backend/src/routes/aggregators/appSetData.ts
  backend/src/routes/aggregators/statuses.ts
  backend/src/routes/ansibletower.ts
  backend/src/routes/operatorCheck.ts
  backend/src/routes/rosaWizardApi.ts
  backend/src/routes/upgrade-risks-prediction.ts
  backend/src/routes/userpreference.ts
)

for file in "${files[@]}"; do
  echo "===== $file ====="
  sed -n '1,180p' "$file" | cat -n
  echo
done

Repository: stolostron/console

Length of output: 39148


Decode request bodies before concatenation.

These handlers still collect req.on('data') chunks as strings without setEncoding('utf8') or a single Buffer.concat(...).toString('utf8') pass. Split multibyte characters can be corrupted before JSON.parse, so valid Unicode payloads may fail or round-trip incorrectly. Apply the same fix to the other body collectors in this change.

📍 Affects 8 files
  • backend/src/lib/pagination.ts#L67-L67 (this comment)
  • backend/src/routes/aggregators/appSetData.ts#L36-L36
  • backend/src/routes/aggregators/statuses.ts#L36-L36
  • backend/src/routes/ansibletower.ts#L39-L39
  • backend/src/routes/operatorCheck.ts#L44-L44
  • backend/src/routes/rosaWizardApi.ts#L40-L40
  • backend/src/routes/rosaWizardApi.ts#L76-L76
  • backend/src/routes/upgrade-risks-prediction.ts#L49-L49
  • backend/src/routes/userpreference.ts#L83-L83
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/src/lib/pagination.ts` at line 67, Update each request-body collector
to decode UTF-8 safely before JSON parsing, avoiding string concatenation of raw
chunks that can corrupt split multibyte characters. Apply the same change at
backend/src/lib/pagination.ts:67,
backend/src/routes/aggregators/appSetData.ts:36,
backend/src/routes/aggregators/statuses.ts:36,
backend/src/routes/ansibletower.ts:39, backend/src/routes/operatorCheck.ts:44,
backend/src/routes/rosaWizardApi.ts:40, backend/src/routes/rosaWizardApi.ts:76,
backend/src/routes/upgrade-risks-prediction.ts:49, and
backend/src/routes/userpreference.ts:83 by setting UTF-8 encoding on the request
stream or buffering chunks and decoding once with UTF-8 before
concatenation/JSON.parse.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will be addressed in a follow-up ticket.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@KevinFCormier, acknowledged. The UTF-8-safe decoding improvement remains deferred from this PR. Would you like me to open and assign a GitHub follow-up issue to you with the affected request-body collectors and acceptance criteria?

🐇💭

@sonarqubecloud

Copy link
Copy Markdown

@KevinFCormier
KevinFCormier merged commit 2928bf1 into main Jul 21, 2026
19 of 20 checks passed
@KevinFCormier
KevinFCormier deleted the fix/ACM-38039-chunk-join-separator branch July 21, 2026 17:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants