Skip to content

fix(tsdb): serve dashboard from REST API port for same-origin fetch (#5684)#5775

Merged
renecannao merged 1 commit into
integration/v3.0-batch-2026-05-13from
fix/issue-5684-tsdb-dashboard-same-origin
May 13, 2026
Merged

fix(tsdb): serve dashboard from REST API port for same-origin fetch (#5684)#5775
renecannao merged 1 commit into
integration/v3.0-batch-2026-05-13from
fix/issue-5684-tsdb-dashboard-same-origin

Conversation

@renecannao

@renecannao renecannao commented May 13, 2026

Copy link
Copy Markdown
Contributor

Fixes #5684.

Summary

  • Move the TSDB dashboard HTML and its Chart.bundle.js asset from admin-web_port to admin-restapi_port, so the dashboard's relative-URL fetch() calls are same-origin with the /api/tsdb/* endpoints they need.
  • Remove the now-broken /tsdb route from ProxySQL_HTTP_Server.
  • Rewrite test_tsdb_api-t.cpp to actually exercise the same-origin assumption -- it now parses the live dashboard HTML, extracts every src / href / fetch URL, and GETs each one against the dashboard's origin.

Root cause

The dashboard HTML (lib/TSDB_Dashboard_html.cpp) issues relative-URL requests:

<script src=\"/Chart.bundle.js\"></script>
fetch('/api/tsdb/metrics');
fetch(\`/api/tsdb/query?metric=...&from=...&to=...\`);

Browsers resolve those against the page origin. The dashboard was served from ProxySQL_HTTP_Server (admin-web_port, default 6080) but /api/tsdb/* lives on ProxySQL_RESTAPI_Server (admin-restapi_port, default 6070). Result: every fetch 404'd at :6080/api/tsdb/... and the dashboard rendered "Error loading metrics" in the UI -- exactly what #5684 reported.

The user diagnosed this perfectly: "In the browser console, it seems to be trying to call the API on port 6080, but the API port is 6070 (admin-restapi_port)."

Considered alternatives

Option Why not
Template-substitute restapi_port into the HTML + CORS on the API Two moving parts; CORS preflight gotchas; same-origin is just cleaner
Move the API to web_port instead of the dashboard Breaks every existing script hitting :6070/api/tsdb/*
Register the API on both ports Duplicates handlers across libmicrohttpd and libhttpserver
Reverse-proxy /api/tsdb/* from web_port to restapi_port Too much machinery for one dashboard
Keep dashboard at :6080/tsdb + 302 to :6070/tsdb The feature is completely broken at :6080 today, so there is no working URL to preserve
Move the dashboard to restapi_port (this PR) One-line registration change, no CORS, no JS edits, dashboard's relative URLs just work

Fix

  • lib/ProxySQL_RESTAPI_Server.cpp: add two minimal http_resource subclasses (tsdb_dashboard_resource, tsdb_chart_js_resource) returning TSDB_Dashboard_html_c and Chart_bundle_js_c with proper Content-Type. Register them at /tsdb and /Chart.bundle.js alongside the existing /api/tsdb/* handlers.
  • lib/ProxySQL_HTTP_Server.cpp: remove the /tsdb handler and the now-unused TSDB_Dashboard_html_c extern. Chart.bundle.js stays here too because other web-port dashboards (/, /stats) reference it.
  • include/ProxySQL_RESTAPI_Server.hpp: add two unique_ptr<http_resource> members to own the new resources.

Verification

Local repro with restapi_port=6071, web_port=6081, tsdb-enabled=1:

GET :6071/tsdb              -> 200 (text/html)        # dashboard
GET :6071/Chart.bundle.js   -> 200 (527KB JS)         # asset
GET :6071/api/tsdb/status   -> 200 (JSON, real data)  # API
GET :6081/tsdb              -> 404                    # regression guard
GET :6081/                  -> 200                    # other dashboards unaffected
GET :6081/Chart.bundle.js   -> 200                    # still served on web port

Test plan

The existing test/tap/tests/test_tsdb_api-t.cpp was rewritten to actually catch the bug. It now:

  1. Reads the runtime admin-restapi_port / admin-web_port (honours non-default config).
  2. Asserts /tsdb is reachable on the REST API port and returns HTML.
  3. Parses the live dashboard HTML, extracts every relative URL (src=\"/...\", href=\"/...\", fetch(\"/...\"), and GETs each one against the dashboard's origin. This is the core TSDB dashboard is showing Error loading metrics #5684 assertion -- a 404 here means the dashboard is broken in a browser.
  4. Asserts the dashboard returns 404 on the web port (regression guard against re-introducing the misroute).
  5. /api/tsdb/status returns a JSON object with the five documented keys.
  6. /api/tsdb/metrics returns a JSON array.
  7. /api/tsdb/query returns rows with {ts, metric, labels, value} shape.

Local verification:

Fixed build:    10/10 pass
Reverted build:  5/10 pass  (catches the bug -- the three dashboard-HTML
                            assertions fail because :6071/tsdb is now
                            404, and the same-origin probe fails because
                            the extracted URL set is empty)
  • Local build with PROXYSQL31=1 (required for PROXYSQLTSDB).
  • Local run of test_tsdb_api-t against a manually-configured ProxySQL with tsdb-enabled=1, admin-restapi_enabled=1, admin-web_enabled=1.
  • Bug-revert experiment confirms the test catches the original failure mode.
  • CI green on ai-g1 (where test_tsdb_api-t is registered).

User-facing change

The dashboard URL moves from http://host:admin-web_port/tsdb (broken) to http://host:admin-restapi_port/tsdb (working). The dashboard now requires admin-restapi_enabled=1 instead of admin-web_enabled=1. In practice both flags had to be set for the dashboard to be useful (the JS always needed the API), so this is not a new requirement.

Summary by CodeRabbit

  • New Features

    • TSDB dashboard and Chart.bundle.js resources are now served through dedicated REST API server endpoints, providing improved cross-origin support and enhanced compatibility for dashboard operations.
  • Bug Fixes

    • Resolved cross-origin resource conflicts and metric-fetch incompatibilities by moving TSDB dashboard serving from HTTP server to REST API server infrastructure, ensuring proper visualization of metrics and charts.

Review Change Stack

…5684)

The TSDB dashboard HTML was served from admin-web_port (default 6080)
but its JS issues relative-URL fetches:

  <script src="/Chart.bundle.js"></script>
  fetch('/api/tsdb/metrics')
  fetch('/api/tsdb/query?...')

Those URLs resolve against the page origin, so the browser tried to
read /api/tsdb/* from :6080 -- but the endpoints live on
admin-restapi_port (default 6070).  Result: every fetch 404'd and the
dashboard rendered "Error loading metrics".

Move the dashboard and its Chart.bundle.js asset to the REST API
server so the dashboard's relative URLs are same-origin with the
endpoints they need.  This is the smallest change that makes the
feature actually work; backwards-compatibility isn't a constraint
since the feature was completely broken at :6080.

* lib/ProxySQL_RESTAPI_Server.cpp: register /tsdb and /Chart.bundle.js
  resources alongside the existing /api/tsdb/* handlers.
* lib/ProxySQL_HTTP_Server.cpp: remove the now-redundant /tsdb route.
  Chart.bundle.js stays here too because other web-port dashboards
  (e.g. /, /stats) still reference it.
* test/tap/tests/test_tsdb_api-t.cpp: rewrite the existing test to
  pin the new wiring.  In particular, parse the live dashboard HTML,
  extract every src/href/fetch URL, and GET each one against the
  dashboard's origin -- this assertion fails on the pre-fix code and
  passes after.  Verified locally: bug build fails 5/10 assertions,
  fixed build passes 10/10.

User-facing change: the dashboard URL moves from
  http://host:admin-web_port/tsdb     (broken)
to
  http://host:admin-restapi_port/tsdb (working)

The dashboard now requires admin-restapi_enabled=1 instead of
admin-web_enabled=1; in practice both were required for the dashboard
to be useful since the JS needed the API anyway.
@coderabbitai

coderabbitai Bot commented May 13, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

The PR migrates TSDB dashboard serving from the HTTP server to the REST API server and substantially upgrades the regression test. The REST API server now declares and registers two new static asset endpoints (/tsdb dashboard HTML and /Chart.bundle.js), while the HTTP server's old /tsdb handler is removed. The test rewrite introduces dynamic port discovery, richer HTTP response introspection, URL extraction from dashboard HTML, and structured JSON validation of TSDB API responses.

Changes

TSDB Dashboard REST API Migration

Layer / File(s) Summary
TSDB dashboard and Chart.js endpoint implementation
include/ProxySQL_RESTAPI_Server.hpp, lib/ProxySQL_RESTAPI_Server.cpp, lib/ProxySQL_HTTP_Server.cpp
REST API server declares two new private http_resource members (tsdb_dashboard_endpoint, tsdb_chart_js_endpoint), implements static asset handlers with text/html; charset=utf-8 and application/javascript; charset=utf-8 content types, registers /tsdb and /Chart.bundle.js routes in constructor, and HTTP server's old /tsdb handler is removed with a note redirecting to REST API.
TSDB dashboard and API regression test
test/tap/tests/test_tsdb_api-t.cpp
New http_result struct and write_cb/header_cb callbacks support HTTP status, body, and Content-Type extraction; http_get helper returns these structured results; extract_relative_urls() regex-parses dashboard HTML for src, href, and fetch(...) URLs; drain_results() simplifies result set handling; main() performs dynamic port discovery (admin-restapi_port, admin-web_port), validates dashboard HTML and all extracted asset URLs resolve on REST origin, asserts /tsdb returns 404 on web origin, and upgrades API assertions from substring checks to JSON parsing with schema validation for /api/tsdb/status, /api/tsdb/metrics, and /api/tsdb/query.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • sysown/proxysql#5484: Modifies test_tsdb_api-t.cpp to validate TSDB dashboard and REST endpoints with URL construction, auth, and richer HTTP assertions, aligning with this PR's shift of dashboard serving to REST API.
  • sysown/proxysql#5383: Foundational TSDB subsystem PR that established REST/UI wiring; this PR extends it by moving dashboard static assets into REST API server endpoints.

Poem

🐰 The dashboard hops to REST's domain,
Where charts and metrics dance and dance again,
No cross-origin pain, no fetch to bemoan,
The TSDB now has a cleaner home! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 9.09% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main change: moving TSDB dashboard from HTTP server to REST API server port to fix same-origin fetch issues.
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.

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

✨ 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/issue-5684-tsdb-dashboard-same-origin

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.

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request migrates the TSDB dashboard and its associated assets from the main HTTP server to the REST API server to resolve cross-origin issues when fetching metrics. The changes include the addition of new resource handlers in the REST API server and a comprehensive update to the test suite to verify same-origin resolution and JSON response integrity. Review feedback suggests including the header and using a safer lambda for string transformations to avoid potential undefined behavior with signed characters.

Comment on lines +24 to +25
#include <map>
#include <regex>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The header <cctype> should be included to provide the definition for std::tolower used in the header_cb function.

#include <cctype>
#include <map>
#include <regex>

if (colon != string::npos) {
string key = line.substr(0, colon);
string val = line.substr(colon + 1);
std::transform(key.begin(), key.end(), key.begin(), ::tolower);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

Using ::tolower directly with std::transform on a std::string is a common pitfall. If char is signed, passing a negative value to tolower results in undefined behavior. It is safer to use a lambda that casts the input to unsigned char before calling std::tolower.

        std::transform(key.begin(), key.end(), key.begin(), [](unsigned char c){ return std::tolower(c); });

@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

🤖 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 `@test/tap/tests/test_tsdb_api-t.cpp`:
- Line 197: The test constructs web_origin with the wrong protocol (uses
"https://" for ProxySQL's admin web server); update the construction of
web_origin to use "http://" instead of "https://", e.g. build web_origin from
cl.admin_host and web_port using "http://" so subsequent checks (like the 404
check that hits the admin web port) use the correct protocol; verify usage of
web_origin in the test to ensure no other places assume HTTPS.
🪄 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: CHILL

Plan: Pro

Run ID: d60f549f-03ac-489c-9632-9fde3b233b9a

📥 Commits

Reviewing files that changed from the base of the PR and between 9cc20a8 and 798c243.

📒 Files selected for processing (4)
  • include/ProxySQL_RESTAPI_Server.hpp
  • lib/ProxySQL_HTTP_Server.cpp
  • lib/ProxySQL_RESTAPI_Server.cpp
  • test/tap/tests/test_tsdb_api-t.cpp
📜 Review details
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{cpp,h,hpp}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{cpp,h,hpp}: Class names must use PascalCase with protocol prefixes (MySQL_, PgSQL_, ProxySQL_)
Member variables must use snake_case naming convention
Constants and macros must use UPPER_SNAKE_CASE naming convention
Use conditional compilation via #ifdef PROXYSQL31, #ifdef PROXYSQL40, #ifdef PROXYSQLFFTO, #ifdef PROXYSQLTSDB, #ifdef PROXYSQLCLICKHOUSE for feature tier gating in core code

Files:

  • include/ProxySQL_RESTAPI_Server.hpp
  • lib/ProxySQL_HTTP_Server.cpp
  • lib/ProxySQL_RESTAPI_Server.cpp
  • test/tap/tests/test_tsdb_api-t.cpp
**/*.{h,hpp}

📄 CodeRabbit inference engine (CLAUDE.md)

Include guards in header files must use #ifndef __CLASS_*_H pattern

Files:

  • include/ProxySQL_RESTAPI_Server.hpp
test/tap/tests/{test_*,-t}.cpp

📄 CodeRabbit inference engine (CLAUDE.md)

Test files must follow the naming pattern test_*.cpp or *-t.cpp in test/tap/tests/

Files:

  • test/tap/tests/test_tsdb_api-t.cpp
test/tap/tests/*-t.cpp

📄 CodeRabbit inference engine (CLAUDE.md)

Test binaries are built via pattern rule in test/tap/tests/Makefile: make <testname>-t compiles <testname>-t.cpp into <testname>-t without requiring explicit Makefile targets

Files:

  • test/tap/tests/test_tsdb_api-t.cpp
🧠 Learnings (1)
📚 Learning: 2026-01-20T09:34:19.124Z
Learnt from: yuji-hatakeyama
Repo: sysown/proxysql PR: 5307
File: test/tap/tests/reg_test_5306-show_warnings_with_comment-t.cpp:39-48
Timestamp: 2026-01-20T09:34:19.124Z
Learning: In ProxySQL's TAP test suite, resource leaks (e.g., not calling mysql_close() on early return paths) are commonly tolerated because test processes are short-lived and OS frees resources on exit. This pattern applies to all C++ test files under test/tap/tests. When reviewing, recognize this as a project-wide test convention and focus on test correctness and isolation rather than insisting on fixing such leaks in these test files.

Applied to files:

  • test/tap/tests/test_tsdb_api-t.cpp
🔇 Additional comments (13)
include/ProxySQL_RESTAPI_Server.hpp (1)

18-19: LGTM!

lib/ProxySQL_RESTAPI_Server.cpp (3)

460-464: LGTM!


466-482: LGTM!


542-549: LGTM!

lib/ProxySQL_HTTP_Server.cpp (1)

440-443: LGTM!

test/tap/tests/test_tsdb_api-t.cpp (8)

1-22: LGTM!


44-54: LGTM!


56-70: LGTM!


72-100: LGTM!


102-109: LGTM!


114-124: LGTM!


126-189: LGTM!


202-284: LGTM!

sleep(8);

const string restapi_origin = string("http://") + cl.admin_host + ":" + std::to_string(restapi_port);
const string web_origin = string("https://") + cl.admin_host + ":" + std::to_string(web_port);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Incorrect protocol for web_origin.

Line 197 uses https:// for the web server origin, but ProxySQL's admin web server (admin-web_port) serves HTTP by default, not HTTPS. This will cause connection failures when the test attempts to verify the dashboard returns 404 on the web port (line 230).

🔧 Proposed fix
-    const string web_origin     = string("https://") + cl.admin_host + ":" + std::to_string(web_port);
+    const string web_origin     = string("http://") + cl.admin_host + ":" + std::to_string(web_port);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const string web_origin = string("https://") + cl.admin_host + ":" + std::to_string(web_port);
const string web_origin = string("http://") + cl.admin_host + ":" + std::to_string(web_port);
🤖 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 `@test/tap/tests/test_tsdb_api-t.cpp` at line 197, The test constructs
web_origin with the wrong protocol (uses "https://" for ProxySQL's admin web
server); update the construction of web_origin to use "http://" instead of
"https://", e.g. build web_origin from cl.admin_host and web_port using
"http://" so subsequent checks (like the 404 check that hits the admin web port)
use the correct protocol; verify usage of web_origin in the test to ensure no
other places assume HTTPS.

@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
Image 1 Security Hotspot
Image D Security Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Image Catch issues before they fail your Quality Gate with our IDE extension Image SonarQube for IDE

@renecannao
renecannao changed the base branch from v3.0 to integration/v3.0-batch-2026-05-13 May 13, 2026 07:51
@renecannao
renecannao merged commit 07ae4fd into integration/v3.0-batch-2026-05-13 May 13, 2026
46 of 51 checks passed
@renecannao
renecannao deleted the fix/issue-5684-tsdb-dashboard-same-origin branch June 10, 2026 11:16
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.

TSDB dashboard is showing Error loading metrics

1 participant