mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-09-07 08:26:51 +00:00
fix: prevent C# LSP crashes from excessively long URIs
Add URI length validation in diff views and checkpoints to prevent UriFormatException crashes when working with large files. Content is truncated when encoded URIs would exceed safe length limits. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
395f55b31f
commit
abc237870d
3 changed files with 90 additions and 11 deletions
5
.changeset/fix-uri-length-lsp-crash.md
Normal file
5
.changeset/fix-uri-length-lsp-crash.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
"roo-cline": patch
|
||||
---
|
||||
|
||||
Fix C# LSP crashes caused by excessively long URIs in diff views and checkpoints. Added URI length validation to prevent crashes when working with large files by truncating content that would exceed safe URI length limits.
|
||||
|
|
@ -12,6 +12,46 @@ import { getApiMetrics } from "../../shared/getApiMetrics"
|
|||
|
||||
import { DIFF_VIEW_URI_SCHEME } from "../../integrations/editor/DiffViewProvider"
|
||||
|
||||
// Maximum safe URI length to avoid crashes in language servers
|
||||
// Most systems have limits between 2KB-32KB, using conservative 8KB limit
|
||||
const MAX_SAFE_URI_LENGTH = 8192
|
||||
|
||||
/**
|
||||
* Safely creates a diff URI by validating the total URI length.
|
||||
* If the URI would be too long, truncates the content to avoid LSP crashes.
|
||||
*/
|
||||
function createSafeDiffUri(fileName: string, content: string): vscode.Uri {
|
||||
try {
|
||||
const base64Content = Buffer.from(content).toString("base64")
|
||||
const baseUri = `${DIFF_VIEW_URI_SCHEME}:${fileName}`
|
||||
const testUri = vscode.Uri.parse(baseUri).with({ query: base64Content }).toString()
|
||||
|
||||
if (testUri.length <= MAX_SAFE_URI_LENGTH) {
|
||||
return vscode.Uri.parse(baseUri).with({ query: base64Content })
|
||||
}
|
||||
|
||||
// Calculate available space for content after accounting for URI overhead
|
||||
const overhead = baseUri.length + 50 // Extra buffer for URI encoding
|
||||
const maxBase64Length = Math.max(0, MAX_SAFE_URI_LENGTH - overhead)
|
||||
|
||||
// Truncate content to fit within safe URI length
|
||||
const maxContentLength = Math.floor((maxBase64Length * 3) / 4) // Base64 is ~4/3 the size
|
||||
const truncatedContent =
|
||||
content.length > maxContentLength
|
||||
? content.substring(0, maxContentLength) + "\n... [Content truncated to prevent LSP crashes]"
|
||||
: content
|
||||
|
||||
const truncatedBase64 = Buffer.from(truncatedContent).toString("base64")
|
||||
return vscode.Uri.parse(baseUri).with({ query: truncatedBase64 })
|
||||
} catch (error) {
|
||||
console.error(`Failed to create diff URI for ${fileName}:`, error)
|
||||
// Fallback to empty content if all else fails
|
||||
return vscode.Uri.parse(`${DIFF_VIEW_URI_SCHEME}:${fileName}`).with({
|
||||
query: Buffer.from("").toString("base64"),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
import { CheckpointServiceOptions, RepoPerTaskCheckpointService } from "../../services/checkpoints"
|
||||
|
||||
export function getCheckpointService(cline: Task) {
|
||||
|
|
@ -277,12 +317,8 @@ export async function checkpointDiff(cline: Task, { ts, previousCommitHash, comm
|
|||
mode === "full" ? "Changes since task started" : "Changes since previous checkpoint",
|
||||
changes.map((change) => [
|
||||
vscode.Uri.file(change.paths.absolute),
|
||||
vscode.Uri.parse(`${DIFF_VIEW_URI_SCHEME}:${change.paths.relative}`).with({
|
||||
query: Buffer.from(change.content.before ?? "").toString("base64"),
|
||||
}),
|
||||
vscode.Uri.parse(`${DIFF_VIEW_URI_SCHEME}:${change.paths.relative}`).with({
|
||||
query: Buffer.from(change.content.after ?? "").toString("base64"),
|
||||
}),
|
||||
createSafeDiffUri(change.paths.relative, change.content.before ?? ""),
|
||||
createSafeDiffUri(change.paths.relative, change.content.after ?? ""),
|
||||
]),
|
||||
)
|
||||
} catch (err) {
|
||||
|
|
|
|||
|
|
@ -16,6 +16,46 @@ import { DecorationController } from "./DecorationController"
|
|||
|
||||
export const DIFF_VIEW_URI_SCHEME = "cline-diff"
|
||||
|
||||
// Maximum safe URI length to avoid crashes in language servers
|
||||
// Most systems have limits between 2KB-32KB, using conservative 8KB limit
|
||||
const MAX_SAFE_URI_LENGTH = 8192
|
||||
|
||||
/**
|
||||
* Safely creates a diff URI by validating the total URI length.
|
||||
* If the URI would be too long, truncates the content to avoid LSP crashes.
|
||||
*/
|
||||
function createSafeDiffUri(fileName: string, content: string): vscode.Uri {
|
||||
try {
|
||||
const base64Content = Buffer.from(content).toString("base64")
|
||||
const baseUri = `${DIFF_VIEW_URI_SCHEME}:${fileName}`
|
||||
const testUri = vscode.Uri.parse(baseUri).with({ query: base64Content }).toString()
|
||||
|
||||
if (testUri.length <= MAX_SAFE_URI_LENGTH) {
|
||||
return vscode.Uri.parse(baseUri).with({ query: base64Content })
|
||||
}
|
||||
|
||||
// Calculate available space for content after accounting for URI overhead
|
||||
const overhead = baseUri.length + 50 // Extra buffer for URI encoding
|
||||
const maxBase64Length = Math.max(0, MAX_SAFE_URI_LENGTH - overhead)
|
||||
|
||||
// Truncate content to fit within safe URI length
|
||||
const maxContentLength = Math.floor((maxBase64Length * 3) / 4) // Base64 is ~4/3 the size
|
||||
const truncatedContent =
|
||||
content.length > maxContentLength
|
||||
? content.substring(0, maxContentLength) + "\n... [Content truncated to prevent LSP crashes]"
|
||||
: content
|
||||
|
||||
const truncatedBase64 = Buffer.from(truncatedContent).toString("base64")
|
||||
return vscode.Uri.parse(baseUri).with({ query: truncatedBase64 })
|
||||
} catch (error) {
|
||||
console.error(`Failed to create diff URI for ${fileName}:`, error)
|
||||
// Fallback to empty content if all else fails
|
||||
return vscode.Uri.parse(`${DIFF_VIEW_URI_SCHEME}:${fileName}`).with({
|
||||
query: Buffer.from("").toString("base64"),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: https://github.com/cline/cline/pull/3354
|
||||
export class DiffViewProvider {
|
||||
// Properties to store the results of saveChanges
|
||||
|
|
@ -310,14 +350,14 @@ export class DiffViewProvider {
|
|||
indentBy: "",
|
||||
suppressEmptyNode: true,
|
||||
processEntities: false,
|
||||
tagValueProcessor: (name, value) => {
|
||||
tagValueProcessor: (_name, value) => {
|
||||
if (typeof value === "string") {
|
||||
// Only escape <, >, and & characters
|
||||
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">")
|
||||
}
|
||||
return value
|
||||
},
|
||||
attributeValueProcessor: (name, value) => {
|
||||
attributeValueProcessor: (_name, value) => {
|
||||
if (typeof value === "string") {
|
||||
// Only escape <, >, and & characters
|
||||
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">")
|
||||
|
|
@ -444,9 +484,7 @@ export class DiffViewProvider {
|
|||
|
||||
vscode.commands.executeCommand(
|
||||
"vscode.diff",
|
||||
vscode.Uri.parse(`${DIFF_VIEW_URI_SCHEME}:${fileName}`).with({
|
||||
query: Buffer.from(this.originalContent ?? "").toString("base64"),
|
||||
}),
|
||||
createSafeDiffUri(fileName, this.originalContent ?? ""),
|
||||
uri,
|
||||
`${fileName}: ${fileExists ? "Original ↔ Roo's Changes" : "New File"} (Editable)`,
|
||||
{ preserveFocus: true },
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue