Skip to content

Conversation

@bneradt
Copy link
Contributor

@bneradt bneradt commented Dec 9, 2025

The xdebug plugin was incorrectly escaping single quotes as ' in probe-full-json output, which is not a valid JSON escape sequence and broke JSON parsing for headers like Content-Security-Policy that contain CSP directives with single quotes (e.g., 'self', 'unsafe-inline'). This fix modifies the EscapeCharForJson class to only escape single quotes in legacy probe format (which uses single-quoted strings) while leaving them unescaped in full JSON mode, producing RFC 8259-compliant JSON output that can be piped directly to tools like jq.

@bneradt bneradt added this to the 10.2.0 milestone Dec 9, 2025
@bneradt bneradt self-assigned this Dec 9, 2025
@bneradt bneradt added Bug xdebug xdebug plugin labels Dec 9, 2025
The xdebug plugin was incorrectly escaping single quotes as \' in
probe-full-json output, which is not a valid JSON escape sequence and
broke JSON parsing for headers like Content-Security-Policy that contain
CSP directives with single quotes (e.g., 'self', 'unsafe-inline'). This
fix modifies the EscapeCharForJson class to only escape single quotes in
legacy probe format (which uses single-quoted strings) while leaving
them unescaped in full JSON mode, producing RFC 8259-compliant JSON
output that can be piped directly to tools like jq.
@bneradt bneradt force-pushed the fix_x_debug_json_parsing branch from 0732363 to f51fa46 Compare December 9, 2025 23:48
Comment on lines +60 to +74
switch (c) {
case '"':
return {"\\\""};
case '\\':
return {"\\\\"};
case '\b':
return {"\\b"};
case '\f':
return {"\\f"};
case '\t':
return {"\\t"};
default:
return {&c, 1};
}
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This got moved to it's own file for unit testability reasons. But the only functional change in this patch is that \' is no longer escaped.

Comment on lines -81 to -82
case '\'':
return {"\\\'"};
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is not in the new switch (see the xdebug_escape.cc version).

@bryancall bryancall requested a review from Copilot December 15, 2025 20:09
Copy link
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

This PR fixes a JSON compliance issue in the xdebug plugin's probe-full-json output where single quotes were incorrectly being escaped as \', which is not valid JSON according to RFC 8259. The fix ensures that single quotes in HTTP headers (like Content-Security-Policy directives containing 'self', 'unsafe-inline') are left unescaped in full JSON mode, producing valid JSON that can be piped to tools like jq.

Key Changes:

  • Removed single quote escaping logic from EscapeCharForJson class to produce RFC 8259-compliant JSON output
  • Refactored escaping code by moving EscapeCharForJson from xdebug_headers.cc to new xdebug_escape.h/cc files
  • Added comprehensive unit tests and integration tests to validate proper handling of single quotes in both legacy probe and full JSON modes

Reviewed changes

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

Show a summary per file
File Description
plugins/xdebug/xdebug_escape.h New header file defining the refactored EscapeCharForJson class with proper documentation
plugins/xdebug/xdebug_escape.cc Implementation of EscapeCharForJson without single quote escaping to ensure JSON compliance
plugins/xdebug/xdebug_headers.h Updated to include new xdebug_escape.h header and removed local FULL_JSON constant
plugins/xdebug/xdebug_headers.cc Removed EscapeCharForJson class definition (moved to separate files)
plugins/xdebug/unit_tests/test_xdebug_utils.cc Added comprehensive unit tests for character escaping logic in both JSON and legacy modes
plugins/xdebug/CMakeLists.txt Updated build configuration to include new xdebug_escape.cc source file
tests/gold_tests/pluginTest/xdebug/x_probe_full_json/x_probe_full_json.test.py Added integration test for CSP headers with single quotes to validate JSON output
tests/gold_tests/pluginTest/xdebug/x_probe_full_json/x_probe_full_json.replay.yaml Added test case for CSP header with single quotes and updated binary data test expectations
tests/gold_tests/pluginTest/xdebug/x_probe_full_json/gold/jq_hex.gold Updated expected output for hex-encoded binary data test

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

content:
encoding: plain
data: "Binary data with quotes!"
data: '"Binary data with quotes!"'
Copy link

Copilot AI Dec 15, 2025

Choose a reason for hiding this comment

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

The binary data content has been changed from plain text to a quoted string, which alters the actual binary content being tested. This changes the hex encoding and may not accurately test the original binary data scenario. The quotes should be removed to preserve the original test intent.

Suggested change
data: '"Binary data with quotes!"'
data: Binary data with quotes!

Copilot uses AI. Check for mistakes.
content:
# Expect hex encoding: "Binary data with quotes!" -> hex
data: '42696e617279206461746120776974682071756f74657321'
data: '"2242696e617279206461746120776974682071756f7465732122",'
Copy link

Copilot AI Dec 15, 2025

Choose a reason for hiding this comment

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

The expected hex output includes leading and trailing quote characters (22 hex = double quote) that were not in the original test data. The hex string should represent only 'Binary data with quotes!' without the added surrounding quotes, unless the source data at line 120 is corrected to remove its added quotes.

Copilot uses AI. Check for mistakes.
Copy link
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 9 out of 9 changed files in this pull request and generated 3 comments.


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

Comment on lines +60 to +73
switch (c) {
case '"':
return {"\\\""};
case '\\':
return {"\\\\"};
case '\b':
return {"\\b"};
case '\f':
return {"\\f"};
case '\t':
return {"\\t"};
default:
return {&c, 1};
}
Copy link

Copilot AI Dec 15, 2025

Choose a reason for hiding this comment

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

The removal of single quote escaping breaks the legacy probe format. The legacy format uses single-quoted strings (e.g., 'header' : 'value'), so single quotes within values must be escaped to prevent premature string termination. For example, a Content-Security-Policy header with value "default-src 'self'" would produce invalid output: 'content-security-policy' : 'default-src 'self'' where the inner 'self' breaks the string. Single quote escaping should be conditionally applied based on the _full_json flag: escape in legacy mode (!_full_json) but not in full JSON mode.

Copilot uses AI. Check for mistakes.
Comment on lines +239 to +244
R"('self')"},

{"legacy: CSP header with multiple single-quoted directives",
!xdebug::FULL_JSON,
R"(child-src blob: 'self'; connect-src 'self' 'unsafe-inline')",
R"(child-src blob: 'self'; connect-src 'self' 'unsafe-inline')"},
Copy link

Copilot AI Dec 15, 2025

Choose a reason for hiding this comment

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

These test cases incorrectly expect single quotes to NOT be escaped in legacy mode. Since the legacy probe format uses single-quoted strings, single quotes within values must be escaped to prevent breaking the string delimiters. These tests should expect the single quotes to be escaped as ' in legacy mode (when full_json is false).

Suggested change
R"('self')"},
{"legacy: CSP header with multiple single-quoted directives",
!xdebug::FULL_JSON,
R"(child-src blob: 'self'; connect-src 'self' 'unsafe-inline')",
R"(child-src blob: 'self'; connect-src 'self' 'unsafe-inline')"},
R"(\'self\')"},
{"legacy: CSP header with multiple single-quoted directives",
!xdebug::FULL_JSON,
R"(child-src blob: 'self'; connect-src 'self' 'unsafe-inline')",
R"(child-src blob: \'self\'; connect-src \'self\' \'unsafe-inline\')"},

Copilot uses AI. Check for mistakes.
{
// clang-format off
static std::vector<EscapeTestCase> const tests = {
// Single quotes are NOT escaped in either mode.
Copy link

Copilot AI Dec 15, 2025

Choose a reason for hiding this comment

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

This comment is incorrect and misleading. Single quotes should be escaped in legacy mode (which uses single-quoted strings) but not in full JSON mode (which uses double-quoted strings per RFC 8259). The comment should clarify that single quotes are escaped differently based on the format.

Suggested change
// Single quotes are NOT escaped in either mode.
// Single quotes are not escaped in either legacy or full JSON mode in this implementation.
// Note: Per RFC 8259, single quotes do not require escaping in full JSON mode (which uses double quotes).
// In legacy mode (which may use single-quoted strings), escaping may be required for strict compatibility,
// but this implementation does not escape them in either mode.

Copilot uses AI. Check for mistakes.
Copy link
Contributor

@masaori335 masaori335 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Bug xdebug xdebug plugin

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants