Skip to content

[fix] Fixed indefinite loading on mixed content exception #602#1063

Open
prathmeshkulkarni-coder wants to merge 7 commits into
openwisp:masterfrom
prathmeshkulkarni-coder:fix/602-mixed-content-exception
Open

[fix] Fixed indefinite loading on mixed content exception #602#1063
prathmeshkulkarni-coder wants to merge 7 commits into
openwisp:masterfrom
prathmeshkulkarni-coder:fix/602-mixed-content-exception

Conversation

@prathmeshkulkarni-coder
Copy link
Copy Markdown
Contributor

@prathmeshkulkarni-coder prathmeshkulkarni-coder commented Mar 17, 2026

When the application is served via HTTPS but the portal API uses HTTP, the browser blocks the request. This fix catches the exception, clears the loading overlay, and notifies the user via a toast message.

Fixes #602

Checklist

  • I have read the OpenWISP Contributing Guidelines.
  • I have manually tested the changes proposed in this pull request.
  • I have written new test cases for new code and/or updated existing tests for changes to existing code.
  • I have updated the documentation.

Reference to Existing Issue

Closes #602

Description of Changes

The Issue: When the application is served over HTTPS but the captive portal endpoints are served via HTTP, the browser's Security Policy blocks the insecure form submission. Previously, because form.submit() is a native browser navigation action (a "fire and forget" mechanism that doesn't return a Promise), it swallowed the Mixed Content network exception. Because the error wasn't caught by the try/catch block, the setLoading(false) was never triggered, leaving the user with an indefinite loading overlay and no error feedback.

The Solution: Instead of replacing the native submit() with an AJAX fetch() (which would break the required iframe onLoad handling and duplicate the captive portal authentication payloads), this PR implements a surgical URL Protocol Validator immediately before the form submission is triggered.

  • Synchronous Protocol Checking: The code now extracts the action URL from the form ref and compares its protocol against window.location.protocol.
  • Explicit Exception Handling: If there is a mismatch (https: trying to submit to http:), the code explicitly throws a new Error("Mixed Content...") before .submit() fires.
  • User Feedback: This custom error is successfully caught by the existing try/catch block, which safely disables the loading spinner and displays the security error to the user via a toast.error() notification.
    This ensures the user is accurately notified of the security exception while keeping the legacy Captive Portal iframe injection flows perfectly intact.

Screenshot

Please include any relevant screenshots.

When the application is served via HTTPS but the portal API uses HTTP,
the browser blocks the request. This fix catches the exception, clears
the loading overlay, and notifies the user via a toast message.

Fixes openwisp#602
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 17, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a new utility checkMixedContent(actionUrl) in client/utils/check-mixed-content.js and integrates it into form submission flows. Components updated: client/components/status/status.js gains submitCaptivePortalForm(formRef) and uses it for captive-portal login/logout and session logout; client/components/login/login.js wraps the Radius realms form submission with the same check. Tests added/updated for checkMixedContent, the new error path in Status, and the Radius login handler.

Sequence Diagram(s)

sequenceDiagram
    participant UI as Client UI
    participant Status as Status Component
    participant Check as checkMixedContent
    participant Browser as Browser
    participant Server as Server

    UI->>Status: submitCaptivePortalForm(formRef)
    Status->>Check: checkMixedContent(formRef.current.action)
    alt Mixed Content detected (HTTPS page, http: action)
        Check-->>Status: throw MixedContentError
        Status->>UI: setLoading(false)
        Status->>UI: toast.error("Security/Network Error: ...")
        Status->>Status: console.error(error)
        Status-->>UI: return false
    else No mixed content
        Status->>Browser: formRef.current.submit()
        Browser->>Server: POST to actionUrl
        Server-->>Browser: response
        Browser-->>Status: navigation/response handling
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The PR title clearly and accurately summarizes the main change: fixing indefinite loading when a mixed content exception occurs, with the issue reference #602.
Description check ✅ Passed The description is comprehensive and addresses all key template sections: checklist items completed, issue reference, and detailed explanation of problem and solution.
Linked Issues check ✅ Passed The PR fully addresses issue #602's requirements: detects mixed content when HTTPS app submits to HTTP endpoints, notifies user via toast error, and clears loading overlay.
Out of Scope Changes check ✅ Passed All code changes are directly scoped to mixed content detection and handling for captive portal login/logout; no unrelated or extraneous modifications found.
Bug Fixes ✅ Passed Pull request correctly fixes mixed content bug with synchronous validation before form submission that throws catchable error, with comprehensive unit tests verifying proper error handling and deterministic test coverage without flakiness concerns.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@openwisp-companion
Copy link
Copy Markdown

Test Failures and Linting Errors

Hello @prathmeshkulkarni-coder,
(Analysis for commit ecf0a4e)

  • Test Failures: Multiple tests in client/components/status/status.test.js are failing because assertions expect a call count of 1, but received 0. This indicates that certain functions or mocks are not being called as expected during the test execution.

  • Fix: Review the test cases should perform captive portal logout (sync auth), should initiate bank_card verification, should logout if mustLogout is true, should logout if activeSession do not contain current MAC, should repeat login if mustLogout and repeatLogin are true, test handleLogout internetMode, should submit logoutForm in iframe on calling handleSessionLogout, and should clear userData on logout. Ensure the logic within these tests correctly sets up the conditions for the expected function calls and that the functions themselves are implemented correctly to be invoked.

  • Linting Errors: The eslint check failed due to two "Must use destructuring context assignment" errors in client/components/status/status.js.

  • Fix: Update the code at lines 249 and 618 in client/components/status/status.js to use destructuring for context assignments as required by the react/destructuring-assignment rule.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
client/components/status/status.js (1)

933-952: ⚠️ Potential issue | 🔴 Critical

Critical: Missing return in catch block causes loading state to be immediately re-enabled.

After catching the mixed content error:

  1. Line 945 sets setLoading(false)
  2. Line 949 (outside the if block) sets setLoading(true) — this overrides the fix
  3. Lines 950-952 continue to make API calls

The user will still see an indefinite loading overlay, defeating the purpose of this fix.

Additionally, the error handling is inconsistent with the other two locations — missing the "Security/Network Error:" prefix and console.error logging.

Proposed fix
       try {
         const formAction = new URL(this.logoutFormRef.current.action);
         if (
           window.location.protocol === "https:" &&
           formAction.protocol === "http:"
         ) {
           throw new Error(
             "Mixed Content: Cannot submit insecure HTTP form from a secure HTTPS page.",
           );
         }
         this.logoutFormRef.current.submit();
       } catch (error) {
         setLoading(false);
-        toast.error(error.message);
+        toast.error(`Security/Network Error: ${error.message}`);
+        console.error("Mixed Content Exception:", error);
+        return;
       }
     }
     setLoading(true);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@client/components/status/status.js` around lines 933 - 952, The catch block
for the logout flow (around logoutFormRef.current.submit()) fails to stop
further execution and re-enables loading; modify the catch to log the error with
console.error, prefix the toast message with "Security/Network Error: "
(consistent with other handlers), call setLoading(false) if not already, and
then return immediately to prevent executing getUserPastRadiusSessions,
getUserActiveRadiusSessions and the later setLoading(true); ensure the unique
symbols referenced are logoutFormRef, setLoading, toast.error,
getUserPastRadiusSessions and getUserActiveRadiusSessions so the early-return
and logging are applied in the same catch scope where the mixed-content error is
thrown.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@client/components/status/status.js`:
- Around line 237-252: Extract the repeated mixed-content validation into a
single helper method (e.g., submitFormWithMixedContentCheck(form)) that accepts
an HTMLFormElement, performs the URL/protocol check (throwing the existing Error
message when page is HTTPS but form.action is HTTP), and calls form.submit() on
success; then replace the duplicated blocks in componentDidMount, handleLogout,
and handleSessionLogout to call this helper with this.loginFormRef.current and
keep the existing try/catch behavior (this.context.setLoading(false),
toast.error(...), console.error(...)) at each call site for consistent error
handling.
- Line 618: Replace the direct property call this.context.setLoading(false) with
the already-destructured setLoading(false) to use the local variable from the
earlier destructuring; update the call in the method where setLoading was
extracted so it calls setLoading(false) instead of
this.context.setLoading(false).
- Line 249: Replace the direct usage of this.context.setLoading with the already
destructured setLoading variable to satisfy the lint rule and maintain
consistency; locate where setLoading was destructured (earlier in the same
module) and change the call this.context.setLoading(false) to setLoading(false)
(ensure there are no naming conflicts and that setLoading is in scope where it's
used).

---

Outside diff comments:
In `@client/components/status/status.js`:
- Around line 933-952: The catch block for the logout flow (around
logoutFormRef.current.submit()) fails to stop further execution and re-enables
loading; modify the catch to log the error with console.error, prefix the toast
message with "Security/Network Error: " (consistent with other handlers), call
setLoading(false) if not already, and then return immediately to prevent
executing getUserPastRadiusSessions, getUserActiveRadiusSessions and the later
setLoading(true); ensure the unique symbols referenced are logoutFormRef,
setLoading, toast.error, getUserPastRadiusSessions and
getUserActiveRadiusSessions so the early-return and logging are applied in the
same catch scope where the mixed-content error is thrown.
🪄 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: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: ae2df772-856b-438b-ac39-c4267a2039a1

📥 Commits

Reviewing files that changed from the base of the PR and between c2813c5 and ecf0a4e.

📒 Files selected for processing (1)
  • client/components/status/status.js
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Tests and Coverage
🧰 Additional context used
🧠 Learnings (5)
📓 Common learnings
Learnt from: nemesifier
Repo: openwisp/openwisp-wifi-login-pages PR: 0
File: :0-0
Timestamp: 2026-03-06T23:26:11.526Z
Learning: In client/components/status/status.js (openwisp-wifi-login-pages), catch blocks deliberately do NOT check `isComponentMounted` — console warnings from catch paths are considered harmless. Only real memory leaks (timers, event listeners) and "setState on unmounted" in success paths are fixed. The maintainer (nemesifier) explicitly wants to avoid over-engineering with defensive checks in every catch block.
📚 Learning: 2026-03-06T23:26:11.526Z
Learnt from: nemesifier
Repo: openwisp/openwisp-wifi-login-pages PR: 0
File: :0-0
Timestamp: 2026-03-06T23:26:11.526Z
Learning: In client/components/status/status.js (openwisp-wifi-login-pages), `finalOperations()` has a single early return before setting up intervals/listeners to prevent the scenario where the component unmounts during async awaits. `safeSetState` is applied to success paths in `getUserRadiusSessions()`, `getUserRadiusUsage()`, `getPlansSuccessCallback()`, and `handlePostMessage()`.

Applied to files:

  • client/components/status/status.js
📚 Learning: 2026-03-06T23:26:11.526Z
Learnt from: nemesifier
Repo: openwisp/openwisp-wifi-login-pages PR: 0
File: :0-0
Timestamp: 2026-03-06T23:26:11.526Z
Learning: In client/components/status/status.js (openwisp-wifi-login-pages), catch blocks deliberately do NOT check `isComponentMounted` — console warnings from catch paths are considered harmless. Only real memory leaks (timers, event listeners) and "setState on unmounted" in success paths are fixed. The maintainer (nemesifier) explicitly wants to avoid over-engineering with defensive checks in every catch block.

Applied to files:

  • client/components/status/status.js
📚 Learning: 2026-03-06T23:26:11.526Z
Learnt from: nemesifier
Repo: openwisp/openwisp-wifi-login-pages PR: 0
File: :0-0
Timestamp: 2026-03-06T23:26:11.526Z
Learning: In client/components/status/status.js (openwisp-wifi-login-pages), the Status component uses `this.isComponentMounted` (set to `true` in the constructor, `false` in `componentWillUnmount`) together with a `safeSetState()` helper method that checks `isComponentMounted` before calling `setState()`. This is the preferred pattern to guard against "setState on unmounted component" warnings.

Applied to files:

  • client/components/status/status.js
📚 Learning: 2026-03-06T23:26:11.526Z
Learnt from: nemesifier
Repo: openwisp/openwisp-wifi-login-pages PR: 0
File: :0-0
Timestamp: 2026-03-06T23:26:11.526Z
Learning: In client/components/status/status.js (openwisp-wifi-login-pages), real memory leaks are fixed by calling `clearTimeout(this.usageRetryTimeoutId)` and `window.removeEventListener("message", ...)` in `componentWillUnmount()`. These were actual leaks — the retry timeout could fire and the message handler could run after unmount.

Applied to files:

  • client/components/status/status.js
🪛 GitHub Check: QA-Checks
client/components/status/status.js

[failure] 249-249:
Must use destructuring context assignment


[failure] 618-618:
Must use destructuring context assignment

Comment thread client/components/status/status.js Outdated
Comment thread client/components/status/status.js Outdated
Comment thread client/components/status/status.js Outdated
@openwisp-companion
Copy link
Copy Markdown

Test Failures in Status Component

Hello @prathmeshkulkarni-coder,
(Analysis for commit 129bbbd)

The tests for the <Status /> component are failing. It appears that several assertions related to function call counts and expected values are not being met.

Specifically, the following tests are failing:

  • should perform captive portal login (submit loginFormRef), if user is just authenticated: spyFn.mock.calls.length is expected to be 1, but received 0.
  • should perform captive portal login (sync auth), if user is just authenticated: loginFormSubmit.mock.calls.length is expected to be 1, but received 0.
  • should fallback to localStorage if cookies are not available (sync auth): handleLoginMock was expected to be called 0 times, but was called 1 time.
  • should perform captive portal logout (sync auth): logoutFormRef.mock.calls.length is expected to be 1, but received 0.
  • should initiate bank_card verification: spyFn.mock.calls.length is expected to be 1, but received 0.
  • should logout if mustLogout is true: mockRef.submit.mock.calls.length is expected to be 1, but received 0.
  • should logout if activeSession do not contain current MAC: localStorage is expected to be {userAutoLogin: "true"}, but received {default_mustLogout: "true", userAutoLogin: "true"}.
  • should repeat login if mustLogout and repeatLogin are true: mockRef.submit.mock.calls.length is expected to be 1, but received 0.
  • test handleLogout internetMode: mockRef.submit was expected to be called 1 time, but was called 0 times.
  • should submit logoutForm in iframe on calling handleSessionLogout: mockRef.submit was expected to be called with no arguments, but it was not called at all.
  • should clear userData on logout: setUserData was expected to be called at least once, but was called 0 times.

To fix these failures, you will need to examine the logic within the <Status /> component and its associated test utilities. Specifically, ensure that the mocks and spies are being called as expected by the test assertions. Debugging the component's behavior during these test scenarios will be necessary to identify the root cause of why the expected calls are not being made or why the received values differ from the expected ones.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@client/components/status/status.js`:
- Around line 929-935: The catch block for the logout flow should match other
sites: add a console.error call with a label (e.g., console.error("Mixed Content
Exception:", error)) for debugging and change the toast message to include the
same prefix ("Security/Network Error: " + error.message) before calling
setLoading(false) and toast.error; locate the try/catch around
checkMixedContent(this.logoutFormRef.current.action) /
this.logoutFormRef.current.submit() and update the catch to log the error and
prepend the "Security/Network Error:" prefix when calling toast.error to ensure
consistency with the other handlers.
🪄 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: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: db45f045-365d-4009-8b76-a58040b7b72a

📥 Commits

Reviewing files that changed from the base of the PR and between ecf0a4e and 129bbbd.

📒 Files selected for processing (1)
  • client/components/status/status.js
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Tests and Coverage
🧰 Additional context used
🧠 Learnings (4)
📚 Learning: 2026-03-06T23:26:11.526Z
Learnt from: nemesifier
Repo: openwisp/openwisp-wifi-login-pages PR: 0
File: :0-0
Timestamp: 2026-03-06T23:26:11.526Z
Learning: In client/components/status/status.js (openwisp-wifi-login-pages), `finalOperations()` has a single early return before setting up intervals/listeners to prevent the scenario where the component unmounts during async awaits. `safeSetState` is applied to success paths in `getUserRadiusSessions()`, `getUserRadiusUsage()`, `getPlansSuccessCallback()`, and `handlePostMessage()`.

Applied to files:

  • client/components/status/status.js
📚 Learning: 2026-03-06T23:26:11.526Z
Learnt from: nemesifier
Repo: openwisp/openwisp-wifi-login-pages PR: 0
File: :0-0
Timestamp: 2026-03-06T23:26:11.526Z
Learning: In client/components/status/status.js (openwisp-wifi-login-pages), catch blocks deliberately do NOT check `isComponentMounted` — console warnings from catch paths are considered harmless. Only real memory leaks (timers, event listeners) and "setState on unmounted" in success paths are fixed. The maintainer (nemesifier) explicitly wants to avoid over-engineering with defensive checks in every catch block.

Applied to files:

  • client/components/status/status.js
📚 Learning: 2026-03-06T23:26:11.526Z
Learnt from: nemesifier
Repo: openwisp/openwisp-wifi-login-pages PR: 0
File: :0-0
Timestamp: 2026-03-06T23:26:11.526Z
Learning: In client/components/status/status.js (openwisp-wifi-login-pages), the Status component uses `this.isComponentMounted` (set to `true` in the constructor, `false` in `componentWillUnmount`) together with a `safeSetState()` helper method that checks `isComponentMounted` before calling `setState()`. This is the preferred pattern to guard against "setState on unmounted component" warnings.

Applied to files:

  • client/components/status/status.js
📚 Learning: 2026-03-06T23:26:11.526Z
Learnt from: nemesifier
Repo: openwisp/openwisp-wifi-login-pages PR: 0
File: :0-0
Timestamp: 2026-03-06T23:26:11.526Z
Learning: In client/components/status/status.js (openwisp-wifi-login-pages), real memory leaks are fixed by calling `clearTimeout(this.usageRetryTimeoutId)` and `window.removeEventListener("message", ...)` in `componentWillUnmount()`. These were actual leaks — the retry timeout could fire and the message handler could run after unmount.

Applied to files:

  • client/components/status/status.js
🔇 Additional comments (3)
client/components/status/status.js (3)

41-51: LGTM! Helper correctly detects mixed content.

The helper function properly identifies the HTTPS→HTTP mixed content scenario that browsers block. One edge case to note: if actionUrl is empty or invalid, new URL(actionUrl) will throw a TypeError, but this is acceptable since the surrounding try-catch will still handle it gracefully and an empty action URL indicates a configuration error that should surface.


249-256: LGTM! Properly guards login form submission.

The try-catch correctly prevents the indefinite loading state by calling setLoading(false) when mixed content is detected, and provides clear user feedback via toast notification.


610-617: LGTM! Consistent error handling for logout form.

The pattern matches the login form handling, ensuring the loading state is properly cleared and the user receives feedback on mixed content errors.

Comment thread client/components/status/status.js Outdated
@prathmeshkulkarni-coder prathmeshkulkarni-coder force-pushed the fix/602-mixed-content-exception branch from 129bbbd to afdf213 Compare March 17, 2026 09:26
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
client/components/status/status.js (1)

930-943: ⚠️ Potential issue | 🟠 Major

Control flow bug: setLoading(true) at line 939 executes after error handling.

When a mixed content error is caught, setLoading(false) is called at line 934, but then setLoading(true) at line 939 executes unconditionally afterward, re-enabling the loading spinner and negating the fix.

The setLoading(true) and subsequent session fetching should either be moved inside the try block (before the check) or the catch block should return early.

🐛 Proposed fix: return early on error
       try {
         checkMixedContent(this.logoutFormRef.current.action);
         this.logoutFormRef.current.submit();
       } catch (error) {
         setLoading(false);
         toast.error(`Security/Network Error: ${error.message}`);
         console.error("Mixed Content Exception:", error);
+        return;
       }
     }
     setLoading(true);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@client/components/status/status.js` around lines 930 - 943, The catch block
for the mixed content check currently calls setLoading(false) but execution
continues and unconditionally calls setLoading(true) and session fetching;
update the control flow so that when checkMixedContent throws you return early
from the function (i.e., add a return in the catch) or move setLoading(true) and
the calls to getUserPastRadiusSessions and getUserActiveRadiusSessions inside
the try block after the check; locate the logic around
checkMixedContent(this.logoutFormRef.current.action), the catch that calls
setLoading(false), and the later
setLoading(true)/getUserPastRadiusSessions/getUserActiveRadiusSessions calls and
ensure you either return from the catch or relocate the setLoading(true)+session
fetches so they only run on success.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@client/components/status/status.js`:
- Around line 930-943: The catch block for the mixed content check currently
calls setLoading(false) but execution continues and unconditionally calls
setLoading(true) and session fetching; update the control flow so that when
checkMixedContent throws you return early from the function (i.e., add a return
in the catch) or move setLoading(true) and the calls to
getUserPastRadiusSessions and getUserActiveRadiusSessions inside the try block
after the check; locate the logic around
checkMixedContent(this.logoutFormRef.current.action), the catch that calls
setLoading(false), and the later
setLoading(true)/getUserPastRadiusSessions/getUserActiveRadiusSessions calls and
ensure you either return from the catch or relocate the setLoading(true)+session
fetches so they only run on success.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 184fc1ce-e79d-45e4-84db-4f4c902c4d90

📥 Commits

Reviewing files that changed from the base of the PR and between 129bbbd and afdf213.

📒 Files selected for processing (1)
  • client/components/status/status.js
📜 Review details
🧰 Additional context used
🧠 Learnings (4)
📚 Learning: 2026-03-06T23:26:11.526Z
Learnt from: nemesifier
Repo: openwisp/openwisp-wifi-login-pages PR: 0
File: :0-0
Timestamp: 2026-03-06T23:26:11.526Z
Learning: In client/components/status/status.js (openwisp-wifi-login-pages), `finalOperations()` has a single early return before setting up intervals/listeners to prevent the scenario where the component unmounts during async awaits. `safeSetState` is applied to success paths in `getUserRadiusSessions()`, `getUserRadiusUsage()`, `getPlansSuccessCallback()`, and `handlePostMessage()`.

Applied to files:

  • client/components/status/status.js
📚 Learning: 2026-03-06T23:26:11.526Z
Learnt from: nemesifier
Repo: openwisp/openwisp-wifi-login-pages PR: 0
File: :0-0
Timestamp: 2026-03-06T23:26:11.526Z
Learning: In client/components/status/status.js (openwisp-wifi-login-pages), catch blocks deliberately do NOT check `isComponentMounted` — console warnings from catch paths are considered harmless. Only real memory leaks (timers, event listeners) and "setState on unmounted" in success paths are fixed. The maintainer (nemesifier) explicitly wants to avoid over-engineering with defensive checks in every catch block.

Applied to files:

  • client/components/status/status.js
📚 Learning: 2026-03-06T23:26:11.526Z
Learnt from: nemesifier
Repo: openwisp/openwisp-wifi-login-pages PR: 0
File: :0-0
Timestamp: 2026-03-06T23:26:11.526Z
Learning: In client/components/status/status.js (openwisp-wifi-login-pages), the Status component uses `this.isComponentMounted` (set to `true` in the constructor, `false` in `componentWillUnmount`) together with a `safeSetState()` helper method that checks `isComponentMounted` before calling `setState()`. This is the preferred pattern to guard against "setState on unmounted component" warnings.

Applied to files:

  • client/components/status/status.js
📚 Learning: 2026-03-06T23:26:11.526Z
Learnt from: nemesifier
Repo: openwisp/openwisp-wifi-login-pages PR: 0
File: :0-0
Timestamp: 2026-03-06T23:26:11.526Z
Learning: In client/components/status/status.js (openwisp-wifi-login-pages), real memory leaks are fixed by calling `clearTimeout(this.usageRetryTimeoutId)` and `window.removeEventListener("message", ...)` in `componentWillUnmount()`. These were actual leaks — the retry timeout could fire and the message handler could run after unmount.

Applied to files:

  • client/components/status/status.js
🔇 Additional comments (3)
client/components/status/status.js (3)

41-52: LGTM! Clean defensive implementation.

The function correctly validates mixed content scenarios with appropriate guards for falsy or non-string inputs. The startsWith("http:") approach is simple and sufficient since form action URLs from the DOM are browser-normalized.


250-257: LGTM! Proper error handling for mixed content detection.

The try-catch correctly wraps the form submission, and the error handling appropriately clears the loading state and provides user feedback via toast notification.


611-618: LGTM! Consistent error handling with other call sites.

The error handling pattern matches the componentDidMount implementation, maintaining consistency across the codebase.

@prathmeshkulkarni-coder
Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 17, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

- Extracted protocol validation into submitWithMixedContentCheck helper.
- Used destructured setLoading to satisfy 'Must use destructuring' rule.
- Fixed duplicated logic in componentDidMount, handleLogout, and handleSessionLogout.

Addresses review feedback for openwisp#602
@prathmeshkulkarni-coder prathmeshkulkarni-coder force-pushed the fix/602-mixed-content-exception branch from afdf213 to beb9d7c Compare March 17, 2026 10:00
Copy link
Copy Markdown
Member

@nemesifier nemesifier left a comment

Choose a reason for hiding this comment

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

Regression test is missing.

Comment thread client/components/status/status.js Outdated
@openwisp-companion
Copy link
Copy Markdown

Commit Message Format Failure

Hello @prathmeshkulkarni-coder,
(Analysis for commit 78cc226)

The commit message is not in the correct format. The issue number must be present in the commit title.

Fix:
Update the commit message to include the issue number in the title.

Example of correct format:

[fix] Refactored mixed-content handling and added regression test #602

- Consolidated duplicated error handling into submitWithMixedContentCheck helper.
- Added a regression test case to verify loading state reset and toast notification
when an insecure form submission is blocked on an HTTPS page.
- Fixed linting by using destructured setLoading throughout the status component.

Fixes #602

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@client/components/status/status.js`:
- Line 264: The mixed-content guard checkMixedContent defined in status.js must
be extracted to a shared utility (e.g., create
client/utils/checkMixedContent.js) and then imported where used; update
submitCaptivePortalForm (in status.js) to call the new shared check and modify
the radius realms submission flow in login.js (the function that currently
submits the radius_realms form directly) to either call the shared
checkMixedContent before submitting or use the same wrapper used by
submitCaptivePortalForm so HTTPS pages cannot post to HTTP actions; ensure you
update imports in both client/components/status/status.js and
client/components/login/login.js and keep the original check logic and
return/early-exit behavior intact.

In `@client/components/status/status.test.js`:
- Around line 2890-2916: The test currently triggers the catch via a mocked
submit() error instead of exercising the mixed-content check; update the test
for submitCaptivePortalForm so checkMixedContent actually runs by setting
window.location.protocol = "https:" (or mocking it) and ensuring the
mockFormRef.current.action is "http://..." so checkMixedContent throws, then
call wrapper.instance().submitCaptivePortalForm(mockFormRef) and assert the same
catch behavior, and finally restore the original window.location.protocol after
the test; refer to submitCaptivePortalForm and checkMixedContent to locate where
to adjust the test setup.
🪄 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: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 4185d8a1-200d-4411-ab41-ad5b0c264f02

📥 Commits

Reviewing files that changed from the base of the PR and between beb9d7c and 78cc226.

📒 Files selected for processing (2)
  • client/components/status/status.js
  • client/components/status/status.test.js
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Tests and Coverage
🧰 Additional context used
🧠 Learnings (5)
📓 Common learnings
Learnt from: nemesifier
Repo: openwisp/openwisp-wifi-login-pages PR: 0
File: :0-0
Timestamp: 2026-03-06T23:26:11.526Z
Learning: In client/components/status/status.js (openwisp-wifi-login-pages), catch blocks deliberately do NOT check `isComponentMounted` — console warnings from catch paths are considered harmless. Only real memory leaks (timers, event listeners) and "setState on unmounted" in success paths are fixed. The maintainer (nemesifier) explicitly wants to avoid over-engineering with defensive checks in every catch block.
Learnt from: nemesifier
Repo: openwisp/openwisp-wifi-login-pages PR: 0
File: :0-0
Timestamp: 2026-03-06T23:26:11.526Z
Learning: In client/components/status/status.js (openwisp-wifi-login-pages), `finalOperations()` has a single early return before setting up intervals/listeners to prevent the scenario where the component unmounts during async awaits. `safeSetState` is applied to success paths in `getUserRadiusSessions()`, `getUserRadiusUsage()`, `getPlansSuccessCallback()`, and `handlePostMessage()`.
📚 Learning: 2026-03-06T23:26:11.526Z
Learnt from: nemesifier
Repo: openwisp/openwisp-wifi-login-pages PR: 0
File: :0-0
Timestamp: 2026-03-06T23:26:11.526Z
Learning: In client/components/status/status.js (openwisp-wifi-login-pages), `finalOperations()` has a single early return before setting up intervals/listeners to prevent the scenario where the component unmounts during async awaits. `safeSetState` is applied to success paths in `getUserRadiusSessions()`, `getUserRadiusUsage()`, `getPlansSuccessCallback()`, and `handlePostMessage()`.

Applied to files:

  • client/components/status/status.js
📚 Learning: 2026-03-06T23:26:11.526Z
Learnt from: nemesifier
Repo: openwisp/openwisp-wifi-login-pages PR: 0
File: :0-0
Timestamp: 2026-03-06T23:26:11.526Z
Learning: In client/components/status/status.js (openwisp-wifi-login-pages), catch blocks deliberately do NOT check `isComponentMounted` — console warnings from catch paths are considered harmless. Only real memory leaks (timers, event listeners) and "setState on unmounted" in success paths are fixed. The maintainer (nemesifier) explicitly wants to avoid over-engineering with defensive checks in every catch block.

Applied to files:

  • client/components/status/status.js
  • client/components/status/status.test.js
📚 Learning: 2026-03-06T23:26:11.526Z
Learnt from: nemesifier
Repo: openwisp/openwisp-wifi-login-pages PR: 0
File: :0-0
Timestamp: 2026-03-06T23:26:11.526Z
Learning: In client/components/status/status.js (openwisp-wifi-login-pages), the Status component uses `this.isComponentMounted` (set to `true` in the constructor, `false` in `componentWillUnmount`) together with a `safeSetState()` helper method that checks `isComponentMounted` before calling `setState()`. This is the preferred pattern to guard against "setState on unmounted component" warnings.

Applied to files:

  • client/components/status/status.js
📚 Learning: 2026-03-06T23:26:11.526Z
Learnt from: nemesifier
Repo: openwisp/openwisp-wifi-login-pages PR: 0
File: :0-0
Timestamp: 2026-03-06T23:26:11.526Z
Learning: In client/components/status/status.js (openwisp-wifi-login-pages), real memory leaks are fixed by calling `clearTimeout(this.usageRetryTimeoutId)` and `window.removeEventListener("message", ...)` in `componentWillUnmount()`. These were actual leaks — the retry timeout could fire and the message handler could run after unmount.

Applied to files:

  • client/components/status/status.js
🔇 Additional comments (4)
client/components/status/status.js (4)

41-52: LGTM!

The checkMixedContent function correctly detects mixed content by checking if the page is served over HTTPS while the form action URL uses HTTP. The guard conditions (actionUrl &&, typeof actionUrl === "string") properly handle edge cases.


106-118: LGTM!

The helper method consolidates mixed-content handling with proper error recovery: resets loading state, shows user-friendly toast, logs for debugging, and returns a boolean for callers that need to know the outcome. This addresses the duplicate code concern from past reviews.


618-618: LGTM!

Correctly uses the new wrapper for logout form submission.


930-932: LGTM!

Good use of the return value to exit early if the mixed-content check fails, preventing the subsequent loading state and session fetching logic from executing.

Comment thread client/components/status/status.js
Comment thread client/components/status/status.test.js
@prathmeshkulkarni-coder prathmeshkulkarni-coder force-pushed the fix/602-mixed-content-exception branch from 78cc226 to b3f2e8a Compare March 18, 2026 17:36
@openwisp-companion
Copy link
Copy Markdown

QA and Test Failures

Hello @prathmeshkulkarni-coder,
(Analysis for commit b3f2e8a)

  1. Code Style/QA Failure:
    The Prettier check failed for client/components/login/login.test.js and client/components/status/status.test.js.
    Fix: Run openwisp-qa-format to automatically fix code style issues.

  2. Test Failure:
    The test client/components/login/login.test.js failed because it expected a "Mixed Content" error message, but received "error details" instead. This indicates that the error handling or the expected error message in the test is not matching the actual behavior.
    Fix: Update the test to expect "error details" or investigate why the "Mixed Content" error is not being thrown. The relevant line in the test is expect(spyToast.mock.calls[0][0]).toContain("Mixed Content").

@prathmeshkulkarni-coder prathmeshkulkarni-coder force-pushed the fix/602-mixed-content-exception branch from b3f2e8a to 41016d1 Compare March 18, 2026 17:47
@openwisp-companion
Copy link
Copy Markdown

ESLint Unused Variable Failure

Hello @prathmeshkulkarni-coder,
(Analysis for commit 41016d1)

  • Code Style/QA: An ESLint error no-unused-vars was found in client/components/login/login.test.js on line 855. The variable spyToast is assigned a value but not used.
  • Fix: Remove the unused spyToast variable or ensure it is used within the test.

@prathmeshkulkarni-coder prathmeshkulkarni-coder force-pushed the fix/602-mixed-content-exception branch 2 times, most recently from 4f05a9a to ea68fa5 Compare March 18, 2026 18:05
@prathmeshkulkarni-coder
Copy link
Copy Markdown
Contributor Author

@nemesifier I added test case and some coderabbit review .

@atif09
Copy link
Copy Markdown
Contributor

atif09 commented Mar 20, 2026

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 20, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@prathmeshkulkarni-coder prathmeshkulkarni-coder force-pushed the fix/602-mixed-content-exception branch from 91eb275 to 29c2bbc Compare March 21, 2026 14:27
@openwisp-companion
Copy link
Copy Markdown

Browser Test Timeout

Hello @prathmeshkulkarni-coder,
(Analysis for commit 5e6d8a9)

The CI job failed because the browser test timed out while waiting for http://0.0.0.0:8080 to become reachable. This indicates a potential issue with the application not starting up correctly or a network configuration problem within the CI environment.

Action: This appears to be a transient infrastructure issue. The CI has been automatically restarted. If the issue persists, please investigate the application's startup logs for any errors.

…nwisp#602

- Consolidated duplicated error handling into submitWithMixedContentCheck helper.
- Added a regression test case to verify loading state reset and toast notification.
- Fixed linting by using destructured setLoading throughout the status component.

Fixes openwisp#602
@prathmeshkulkarni-coder prathmeshkulkarni-coder force-pushed the fix/602-mixed-content-exception branch from 5e6d8a9 to 4617ce2 Compare March 21, 2026 14:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[bug] Notify user about mixed content exception

3 participants