mirror of
https://github.com/ChromeDevTools/chrome-devtools-mcp.git
synced 2026-09-14 19:45:30 +08:00
fix: truncate long urls in concise network request output (#2513)
## What Implements the existing `// TODO truncate the URL` in `src/formatters/NetworkFormatter.ts`: URLs in the concise one-line network request format are now capped at 150 characters, with the file's existing `getSizeLimitedString` helper appending the same `... <truncated>` marker already used for request/response bodies. ## Why `list_network_requests` emits one concise line per request, so a single page with a few `data:` URLs (which can be tens of kilobytes each) can blow up the tool output by orders of magnitude. Truncating in the concise format keeps list output token-friendly while losing nothing that matters for identifying a request. Scope is deliberately narrow — only `convertNetworkRequestConciseToString` changes: - the detailed view (`## Request <url>` heading) still shows the full URL, and - `toJSON()` / structured content still carries the full URL, so nothing that needs the complete URL is affected. (Concise redirect-chain lines inside the detailed view use the same function and are truncated too, which keeps that list compact as well.) ## Limit rationale 150 characters keeps origin + path + the start of the query string intact for virtually all real-world URLs (typical URLs are well under 100 characters), while capping pathological `data:`/blob payloads. It reuses the existing `getSizeLimitedString` pattern with a new `URL_CONTEXT_SIZE_LIMIT` constant next to `BODY_CONTEXT_SIZE_LIMIT`. ## Before / after Before: ``` reqid=12 GET data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA... (10,000+ more chars) ...5CYII= [200] ``` After: ``` reqid=12 GET data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...(150 chars total)... <truncated> [200] ``` Short URLs are unchanged. ## Testing - `npm run build` — pass - `npm run test:no-build` — pass (all tests, exit 0) - `npm run check-format` — pass (eslint + prettier) Added three cases to `tests/formatters/NetworkFormatter.test.ts`: - long URL is truncated at 150 chars with the `... <truncated>` marker (and `toJSON()` keeps the full URL), - `data:` URL is truncated, - a URL exactly at the limit is left untouched. No existing snapshots changed. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: ZayanKhan-12 <khanzayan200@gmail.com> Co-authored-by: Alex Rudenko <alexrudenko@chromium.org>
This commit is contained in:
@@ -13,6 +13,7 @@ import {
|
||||
} from '../third_party/index.js';
|
||||
|
||||
const BODY_CONTEXT_SIZE_LIMIT = 10000;
|
||||
const URL_CONTEXT_SIZE_LIMIT = 255;
|
||||
|
||||
export interface NetworkFormatterOptions {
|
||||
requestId?: number | string;
|
||||
@@ -263,8 +264,10 @@ function getSizeLimitedString(text: string, sizeLimit: number) {
|
||||
function convertNetworkRequestConciseToString(
|
||||
data: NetworkRequestConcise,
|
||||
): string {
|
||||
// TODO truncate the URL
|
||||
return `reqid=${data.requestId} ${data.method} ${data.url} [${data.status}]${data.selectedInDevToolsUI ? ` [selected in the DevTools Network panel]` : ''}`;
|
||||
// Long URLs (e.g., data: URLs) bloat the concise list output. The full URL
|
||||
// remains available via the detailed view and the structured content.
|
||||
const url = getSizeLimitedString(data.url, URL_CONTEXT_SIZE_LIMIT);
|
||||
return `reqid=${data.requestId} ${data.method} ${url} [${data.status}]${data.selectedInDevToolsUI ? ` [selected in the DevTools Network panel]` : ''}`;
|
||||
}
|
||||
|
||||
function formatHeaders(headers: Record<string, string>): string[] {
|
||||
|
||||
@@ -132,6 +132,51 @@ describe('NetworkFormatter', () => {
|
||||
'reqid=1 GET http://example.com [pending] [selected in the DevTools Network panel]',
|
||||
);
|
||||
});
|
||||
|
||||
it('truncates long urls', async () => {
|
||||
const longUrl = `http://example.com/${'a'.repeat(500)}`;
|
||||
const request = getMockRequest({url: longUrl});
|
||||
const formatter = await NetworkFormatter.from(request, {
|
||||
requestId: 1,
|
||||
saveFile: async () => ({filename: ''}),
|
||||
redactNetworkHeaders: false,
|
||||
});
|
||||
|
||||
assert.equal(
|
||||
formatter.toString(),
|
||||
`reqid=1 GET ${longUrl.substring(0, 255)}... <truncated> [pending]`,
|
||||
);
|
||||
// The structured data keeps the full URL.
|
||||
assert.equal(formatter.toJSON().url, longUrl);
|
||||
});
|
||||
|
||||
it('truncates data: urls', async () => {
|
||||
const dataUrl = `data:image/png;base64,${'A'.repeat(5000)}`;
|
||||
const request = getMockRequest({url: dataUrl});
|
||||
const formatter = await NetworkFormatter.from(request, {
|
||||
requestId: 1,
|
||||
saveFile: async () => ({filename: ''}),
|
||||
redactNetworkHeaders: false,
|
||||
});
|
||||
|
||||
assert.equal(
|
||||
formatter.toString(),
|
||||
`reqid=1 GET ${dataUrl.substring(0, 255)}... <truncated> [pending]`,
|
||||
);
|
||||
});
|
||||
|
||||
it('does not truncate urls within the size limit', async () => {
|
||||
// Exactly at the 150 character limit.
|
||||
const url = `http://example.com/${'a'.repeat(131)}`;
|
||||
const request = getMockRequest({url});
|
||||
const formatter = await NetworkFormatter.from(request, {
|
||||
requestId: 1,
|
||||
saveFile: async () => ({filename: ''}),
|
||||
redactNetworkHeaders: false,
|
||||
});
|
||||
|
||||
assert.equal(formatter.toString(), `reqid=1 GET ${url} [pending]`);
|
||||
});
|
||||
});
|
||||
|
||||
describe('toStringDetailed', () => {
|
||||
|
||||
Reference in New Issue
Block a user