Skip to content

Fix mixed content errors from malformed CDN URLs in protocol-relative and triple-slash URL handling#1049

Merged
selul merged 6 commits intodevelopmentfrom
copilot/fix-mixed-content-errors
Apr 3, 2026
Merged

Fix mixed content errors from malformed CDN URLs in protocol-relative and triple-slash URL handling#1049
selul merged 6 commits intodevelopmentfrom
copilot/fix-mixed-content-errors

Conversation

Copy link
Copy Markdown

Copilot AI commented Apr 2, 2026

  • Fix operator precedence bug in add_schema() in inc/traits/normalizer.php
  • Fix triple-slash URL normalization in build_url() in inc/url_replacer.php
  • Add test_add_schema_non_ssl(), test_add_schema_ssl(), test_add_schema_already_schemed() to tests/test-generic.php
  • Move // / /// scheme normalization before can_replace_url() so parse_url() succeeds on protocol-relative URLs
  • Rewrite triple-slash test as test_build_url_normalizes_triple_slash() — tests build_url() directly with both // and /// inputs
  • Remove redundant assertStringNotEquals in test_add_schema_ssl()
  • E2E failure is infrastructure-only (database connection refused) — not caused by our changes
Original prompt

Summary

This PR fixes two bugs in the Optimole plugin that together cause mixed content errors and broken images in AJAX contexts (e.g., WooCommerce mini-cart loaded via custom admin-ajax actions). Reported by a user on windmeile.com. See issue: #1048


Bug 1: Operator precedence error in add_schema()inc/traits/normalizer.php

File: inc/traits/normalizer.php
Method: add_schema()
Lines: ~374–376

Current (buggy) code:

if ( $should_add_schema ) {
    $schema_url = is_ssl() ? 'https:' : 'http:' . $schema_url;
}

Problem:

Due to PHP operator precedence, . (concatenation) binds tighter than ?: (ternary). So the code is actually evaluated as:

$schema_url = is_ssl() ? 'https:' : ('http:' . $schema_url);

When is_ssl() returns true, $schema_url is set to the bare string 'https:' instead of 'https://…'. The // part is lost entirely.

Fix:

if ( $should_add_schema ) {
    $schema_url = ( is_ssl() ? 'https:' : 'http:' ) . $schema_url;
}

Bug 2: Triple-slash URLs (///host/path) not normalized in build_url()inc/url_replacer.php

File: inc/url_replacer.php
Method: build_url()
Lines: ~156–158

Current (buggy) code:

if ( substr( $url, 0, 2 ) === '//' ) {
    $url = sprintf( '%s:%s', is_ssl() ? 'https' : 'http', $url );
}

Problem:

When a URL has three leading slashes (///windmeile.com/wp-content/uploads/…), substr($url, 0, 2) === '//' is still true, so the code prepends https: to produce https:///windmeile.com/… — a malformed URL with three slashes after the colon. This malformed URL gets embedded into the Optimole CDN URL path. The CDN backend cannot properly resolve this scheme-less/invalid origin URL and falls back to a 302 Location: http://… redirect, causing the browser to see a mixed content error (HTTPS page → HTTP redirect target).

Fix:

Strip all leading slashes before rebuilding the URL with the correct scheme and ://:

if ( substr( $url, 0, 2 ) === '//' ) {
    $url = ltrim( $url, '/' );
    $url = sprintf( '%s://%s', is_ssl() ? 'https' : 'http', $url );
}

Expected outcome after fix

  • Protocol-relative URLs (//host/path) and triple-slash URLs (///host/path) are both correctly normalized to https://host/path (or http:// on non-SSL) before being passed to the Optimole SDK and CDN.
  • The add_schema() helper correctly prepends https: + the original //… string instead of discarding it.
  • No more malformed CDN URLs with /// embedded origin paths.
  • No more 302 Location: http://… fallback redirects causing mixed content errors.
  • Fixes broken mini-cart thumbnails and other AJAX-loaded image contexts.

Files to change

  1. inc/traits/normalizer.php — Fix add_schema() operator precedence (line ~375)
  2. inc/url_replacer.php — Fix triple-slash URL normalization in build_url() (lines ~156–158)

Related

The following is the prior conversation context from the user's chat exploration (may be truncated):

User: check if this is a issue with optimole or not

find the root cause of the mixed content issue on our WooCommerce store (windmeile.com) related to Optimole image URLs generated in an AJAX mini-cart (theme uses a custom admin-ajax action uncode_ajax_add_to_cart). Here is the summary: What happend
The page is loaded via HTTPS.
The mini-cart (loaded via AJAX) contains Optimole CDN URLs like: src="//.i.optimole.com/...///windmeile.com/wp-content/uploads/...png" (CDN URL is protocol-relative //… and the embedded origin part is scheme-less: ///windmeile.com/...)
When the browser requests the CDN URL over HTTPS, Optimole returns a redirect:
Response: 302 Found
Header: Location: http://windmeile.com/wp-content/uploads/...
This produces a browser mixed content error (HTTPS page → resource is redirected to HTTP) and breaks the mini-cart thumbnails. Debugging results (confirmed on our side)
WordPress correctly detects SSL even during the AJAX call (is_ssl() = true, HTTPS=on, SERVER_PORT=443, X-Forwarded-Proto=https).
We verified that the input URL passed into Optimole processing is already HTTPS: https://windmeile.com/wp-content/uploads/...
The problem is reproducible by directly opening the Optimole CDN URL in a new browser tab: it still responds with 302 Location: http://....
If we manually request the http://windmeile.com/... URL, our server redirects it to HTTPS. However, the browser blocks it anyway because the chain starts with an insecure HTTP redirect target.
Conclusion: it appears Optimole cannot properly handle scheme-less embedded origin URLs (///windmeile.com/...) and falls back to an HTTP redirect target instead of HT...

This pull request was created from Copilot chat.

…ation in build_url()

Agent-Logs-Url: https://github.com/Codeinwp/optimole-wp/sessions/b12c03d6-d980-4909-8199-8aafbe58a311

Co-authored-by: kushh23 <110405452+kushh23@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix mixed content errors in Optimole plugin Fix mixed content errors from malformed CDN URLs in protocol-relative and triple-slash URL handling Apr 2, 2026
Copilot AI requested a review from kushh23 April 2, 2026 22:43
@kushh23 kushh23 marked this pull request as ready for review April 2, 2026 22:46
@kushh23 kushh23 requested a review from Copilot April 2, 2026 22:47
@pirate-bot
Copy link
Copy Markdown
Collaborator

pirate-bot commented Apr 2, 2026

Plugin build for 4adf764 is ready 🛎️!

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Fixes malformed Optimole CDN URLs that could lead to HTTPS→HTTP redirects (mixed content) by correcting protocol handling in two normalization paths.

Changes:

  • Fixes add_schema() ternary/concatenation precedence so protocol-relative URLs retain the //... portion when SSL is on.
  • Normalizes triple-slash (///host/path) and protocol-relative (//host/path) inputs in build_url() to a well-formed http(s)://host/path form.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
inc/url_replacer.php Ensures protocol-relative/triple-slash URLs are rebuilt with a valid http(s):// prefix.
inc/traits/normalizer.php Fixes schema-prepending logic so SSL correctly yields https://... for //... URLs.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@kushh23
Copy link
Copy Markdown

kushh23 commented Apr 3, 2026

@copilot lets add those unit tests which were discovered in code review

Copilot AI and others added 2 commits April 3, 2026 10:55
…ple-slash URL normalization

Agent-Logs-Url: https://github.com/Codeinwp/optimole-wp/sessions/0b947f08-2140-4d1b-9330-9381b891257a

Co-authored-by: kushh23 <110405452+kushh23@users.noreply.github.com>
Copy link
Copy Markdown
Author

Copilot AI commented Apr 3, 2026

@copilot lets add those unit tests which were discovered in code review

Added in commit 9e725b8:

  • tests/test-generic.php — Three new tests for add_schema() (uses the Optml_Normalizer trait directly):

    • test_add_schema_non_ssl()//host/pathhttp://host/path
    • test_add_schema_ssl() — regression for the operator-precedence bug: sets $_SERVER['HTTPS'] and asserts //host/pathhttps://host/path (not the bare https:)
    • test_add_schema_already_schemed() — URLs with an existing scheme pass through unchanged
  • tests/test-replacer.phptest_replacement_triple_slash_url(): feeds ///www.example.org/… through the full replacement pipeline and asserts the output contains i.optimole.com, http://www.example.org, and never :///.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…re can_replace_url() and test build_url() directly

Agent-Logs-Url: https://github.com/Codeinwp/optimole-wp/sessions/8939ca95-d282-4d7f-96c9-a37fb5fc50ec

Co-authored-by: kushh23 <110405452+kushh23@users.noreply.github.com>
@kushh23 kushh23 requested a review from selul April 3, 2026 12:18
Copy link
Copy Markdown
Contributor

@selul selul left a comment

Choose a reason for hiding this comment

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

lgtm

@selul selul changed the base branch from master to development April 3, 2026 12:29
@selul selul merged commit 568a15c into development Apr 3, 2026
12 of 13 checks passed
@selul selul deleted the copilot/fix-mixed-content-errors branch April 3, 2026 12:30
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.

Mixed Content and Malformed URLs: Optimole image CDN creates scheme-less URLs, causes HTTPS to HTTP fallback redirects in AJAX/mini-cart

5 participants