Skip to content

feat: add customBaseURL CNAME support to NetworkOptions#701

Open
jamesnrokt wants to merge 2 commits into
mainfrom
feat/cname-custom-base-url
Open

feat: add customBaseURL CNAME support to NetworkOptions#701
jamesnrokt wants to merge 2 commits into
mainfrom
feat/cname-custom-base-url

Conversation

@jamesnrokt
Copy link
Copy Markdown
Collaborator

Summary

Adds NetworkOptions.Builder.setCustomBaseURL(String) which routes all mParticle endpoint traffic (config, events, identity, alias, audience) through a single HTTPS CNAME host. Mirrors iOS work from mparticle-apple-sdk#760.

What changed

  • NetworkOptions: new customBaseURL field + getter; Builder.setCustomBaseURL(@NonNull String) validates HTTPS scheme, requires a host, and stores host(:port) only — path/query/fragment ignored.
  • MParticleBaseClientImpl.getUrl: when customBaseURL is set:
    • Skips the pod prefix (the CNAME's CDN handles regional routing).
    • Logs a warning and ignores any per-endpoint DomainMapping and overridesSubdirectory (unsupported with CDN routing).
    • Rewrites paths to: /config/v4/<key>/config, /nativeevents/v2/<key>/events, /identity/v1/<path>, /nativeevents/v1/identity/<key>/alias, /nativeevents/v1/<key>/audience.
  • android-core/proguard.pro: adds -keep rules for MParticle$Internal and ConfigManager.getNetworkOptions() so downstream kits can navigate the public extension surface after R8 minification.

Downstream

The Rokt kit reads NetworkOptions.customBaseURL and forwards it to the Rokt SDK: mparticle-integrations/mparticle-android-integration-rokt#143

Test plan

Added 9 androidTest cases in MParticleBaseClientImplTest:

  • Custom CNAME routes config endpoint via /config/v4/
  • Custom CNAME routes events endpoint via /nativeevents/v2/
  • Custom CNAME routes identity endpoint via /identity/v1/
  • Custom CNAME routes alias endpoint via /nativeevents/v1/identity/
  • Custom CNAME routes audience endpoint via /nativeevents/v1/<key>/audience
  • Non-HTTPS values rejected
  • Path/query stripped
  • Port preserved
  • Malformed URL rejected

Locally: :android-core:testDebugUnitTest passes (existing unit suite); :android-core:compileDebugAndroidTestKotlin compiles. AndroidTest suite runs on CI emulator.

🤖 Generated with Claude Code

Adds NetworkOptions.Builder.setCustomBaseURL(String) which routes all
mParticle endpoint traffic (config, events, identity, alias, audience)
through a single HTTPS CNAME host. When set, customBaseURL takes
priority over individual domain mappings and rewrites paths to match
CDN routing: /config/v4/, /nativeevents/v2/, /identity/v1/,
/nativeevents/v1/identity/, /nativeevents/v1/<key>/audience.

Also adds R8 keep rules for MParticle$Internal and
ConfigManager.getNetworkOptions() so kits can read customBaseURL after
minification.

The Rokt kit reads NetworkOptions.customBaseURL and forwards it to the
Rokt SDK: mparticle-integrations/mparticle-android-integration-rokt#143

Mirrors iOS work from mparticle-apple-sdk#760.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@jamesnrokt jamesnrokt requested a review from a team as a code owner May 13, 2026 19:28
@cursor
Copy link
Copy Markdown

cursor Bot commented May 13, 2026

PR Summary

Medium Risk
Changes core URL construction for config/events/identity/alias/audience and alters precedence between customBaseURL and per-endpoint domain mappings, which could misroute traffic if misconfigured. Adds new serialization and ProGuard keep rules that may impact downstream minified builds.

Overview
Adds NetworkOptions.Builder.setCustomBaseURL(...) to route all SDK network traffic through a single HTTPS CNAME host, storing only host(:port) and including JSON (de)serialization support.

Updates MParticleBaseClientImpl.getUrl to prefer customBaseURL over per-endpoint DomainMapping, adjust endpoint paths for CDN-style routing (e.g. /config/v4/, /nativeevents/v2/, /identity/v1/), and warn/ignore incompatible overridesSubdirectory/domain-mapping combinations.

Expands androidTests to cover custom-base URL routing, validation (HTTPS/malformed), and JSON round-trips, and adds ProGuard -keep rules to preserve MParticle$Internal and ConfigManager.getNetworkOptions() under R8.

Reviewed by Cursor Bugbot for commit 42fff2a. Bugbot is set up for automated code reviews on this repo. Configure here.

Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 96950e7. Configure here.

thomson-t
thomson-t previously approved these changes May 13, 2026
@NonNull
public Builder setCustomBaseURL(@NonNull String customBaseURL) {
try {
java.net.URL parsed = new java.net.URL(customBaseURL);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

nit: import the class.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Done — imported java.net.URL and java.net.MalformedURLException in 42fff2a.

host.append(":").append(parsed.getPort());
}
this.customBaseURL = host.toString();
} catch (java.net.MalformedURLException e) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

nit: import the class here as well.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Done in 42fff2a.

Comment thread android-core/proguard.pro
Comment on lines +88 to +90
-keep class com.mparticle.internal.ConfigManager {
public com.mparticle.networking.NetworkOptions getNetworkOptions();
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Good catch

Copy link
Copy Markdown

@denischilik denischilik left a comment

Choose a reason for hiding this comment

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

Looks good to me but I think customBaseURL lost during database serialization round-trip should be addressed

NetworkOptions.toJson() and withNetworkOptions(String) did not include
customBaseURL, so any value was silently dropped when UploadSettings
serialized NetworkOptions to the upload database. Events and alias
uploads read back NetworkOptions without customBaseURL and routed to
the default mParticle endpoints instead of the partner CNAME.

Also:
- Extract the customBaseURL/DomainMapping host-resolution branch out of
  getUrl() into a private resolveHost() helper plus a small ResolvedHost
  value type, lowering getUrl()'s cyclomatic complexity.
- Switch java.net.URL / java.net.MalformedURLException to imports.
- Add two androidTest cases covering the round-trip.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@sonarqubecloud
Copy link
Copy Markdown

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.

3 participants