Skip to content

Commit e75e672

Browse files
fix(spx-gui): fix update checker false positive caused by weak ETag prefix (#2979)
* fix update checker false positive caused by weak ETag prefix * remove redundant trim Co-authored-by: xgopilot[bot] <231223108+xgopilot[bot]@users.noreply.github.com> --------- Co-authored-by: xgopilot[bot] <231223108+xgopilot[bot]@users.noreply.github.com>
1 parent 2747dd3 commit e75e672

File tree

2 files changed

+55
-2
lines changed

2 files changed

+55
-2
lines changed

spx-gui/src/components/app/update-check/update-checker.test.ts

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,52 @@ describe('update-checker', () => {
124124
cache: 'no-cache'
125125
})
126126
})
127+
128+
it('should treat weak etag with W/ prefix as unchanged', async () => {
129+
const strongEtag = '"abc123"'
130+
const weakEtag = 'W/"abc123"'
131+
132+
global.fetch = vi.fn().mockResolvedValue({
133+
ok: true,
134+
headers: {
135+
get: (key: string) => (key === 'etag' ? strongEtag : null)
136+
}
137+
})
138+
await checker.checkForUpdates()
139+
140+
global.fetch = vi.fn().mockResolvedValue({
141+
ok: true,
142+
headers: {
143+
get: (key: string) => (key === 'etag' ? weakEtag : null)
144+
}
145+
})
146+
147+
const hasUpdate = await checker.checkForUpdates()
148+
expect(hasUpdate).toBe(false)
149+
})
150+
151+
it('should detect update when weak etag value changes', async () => {
152+
const oldWeakEtag = 'W/"abc123"'
153+
const newWeakEtag = 'W/"def456"'
154+
155+
global.fetch = vi.fn().mockResolvedValue({
156+
ok: true,
157+
headers: {
158+
get: (key: string) => (key === 'etag' ? oldWeakEtag : null)
159+
}
160+
})
161+
await checker.checkForUpdates()
162+
163+
global.fetch = vi.fn().mockResolvedValue({
164+
ok: true,
165+
headers: {
166+
get: (key: string) => (key === 'etag' ? newWeakEtag : null)
167+
}
168+
})
169+
170+
const hasUpdate = await checker.checkForUpdates()
171+
expect(hasUpdate).toBe(true)
172+
})
127173
})
128174

129175
describe('start', () => {

spx-gui/src/components/app/update-check/update-checker.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@ export class UpdateChecker {
1818
private updateCheckTimer: ReturnType<typeof setInterval> | null = null
1919
private currentEtag: string | null = null
2020

21+
/** Normalizes ETag values by removing weak validator prefix and trimming whitespace */
22+
private normalizeEtag(etag: string): string {
23+
const trimmed = etag.trim()
24+
return trimmed.startsWith('W/') ? trimmed.slice(2) : trimmed
25+
}
26+
2127
/**
2228
* Checks if there is a new version of the application available
2329
*
@@ -37,9 +43,10 @@ export class UpdateChecker {
3743
throw new Error('ETag header not found')
3844
}
3945

40-
const hasUpdate = this.currentEtag != null && this.currentEtag !== etag
46+
const normalizedEtag = this.normalizeEtag(etag)
47+
const hasUpdate = this.currentEtag != null && this.currentEtag !== normalizedEtag
4148
// Initialize currentEtag on first check
42-
if (this.currentEtag == null) this.currentEtag = etag
49+
if (this.currentEtag == null) this.currentEtag = normalizedEtag
4350
return hasUpdate
4451
}
4552

0 commit comments

Comments
 (0)