Skip to content

Commit 8ee7656

Browse files
committed
refactor: drop support for weak etags
1 parent a47ea66 commit 8ee7656

File tree

2 files changed

+115
-6
lines changed

2 files changed

+115
-6
lines changed

lib/handler/retry-handler.js

+7-5
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,6 @@ class RetryHandler {
6464
this.start = 0
6565
this.end = null
6666
this.etag = null
67-
this.isWeakEtag = false
6867
this.resume = null
6968

7069
// Handle possible onConnect duplication
@@ -205,7 +204,7 @@ class RetryHandler {
205204
}
206205

207206
// Let's start with a weak etag check
208-
if (this.etag != null && !this.isWeakEtag && this.etag !== headers.etag) {
207+
if (this.etag != null && this.etag !== headers.etag) {
209208
this.abort(
210209
new RequestRetryError('ETag mismatch', statusCode, {
211210
headers,
@@ -264,8 +263,11 @@ class RetryHandler {
264263
this.resume = resume
265264
this.etag = headers.etag != null ? headers.etag : null
266265

267-
if (this.etag != null) {
268-
this.isWeakEtag = this.etag.startsWith('W/')
266+
// Weak etags are not useful for comparison nor cache
267+
// for instance not safe to assume if the response is byte-per-byte
268+
// equal
269+
if (this.etag != null && this.etag.startsWith('W/')) {
270+
this.etag = null
269271
}
270272

271273
return this.handler.onHeaders(
@@ -331,7 +333,7 @@ class RetryHandler {
331333
const headers = { range: `bytes=${this.start}-${this.end ?? ''}` }
332334

333335
// Weak etag check - weak etags will make comparison algorithms never match
334-
if (this.retryOpts.ifMatch && this.etag != null && !this.isWeakEtag) {
336+
if (this.retryOpts.ifMatch && this.etag != null) {
335337
headers['if-match'] = this.etag
336338
}
337339

test/retry-handler.js

+108-1
Original file line numberDiff line numberDiff line change
@@ -1086,6 +1086,113 @@ test('Issue#3128 - Support if-match', async t => {
10861086
await t.completed
10871087
})
10881088

1089+
test('Issue#3128 - Support if-match (disabled)', async t => {
1090+
t = tspl(t, { plan: 9 })
1091+
1092+
const chunks = []
1093+
let counter = 0
1094+
1095+
// Took from: https://github.com/nxtedition/nxt-lib/blob/4b001ebc2f22cf735a398f35ff800dd553fe5933/test/undici/retry.js#L47
1096+
let x = 0
1097+
const server = createServer((req, res) => {
1098+
if (x === 0) {
1099+
t.deepStrictEqual(req.headers.range, 'bytes=0-3')
1100+
res.setHeader('etag', 'asd')
1101+
res.write('abc')
1102+
setTimeout(() => {
1103+
res.destroy()
1104+
}, 1e2)
1105+
} else if (x === 1) {
1106+
t.deepStrictEqual(req.headers.range, 'bytes=3-')
1107+
t.equal(req.headers['if-match'], undefined)
1108+
1109+
res.setHeader('content-range', 'bytes 3-6/6')
1110+
res.setHeader('etag', 'asd')
1111+
res.statusCode = 206
1112+
res.end('def')
1113+
}
1114+
x++
1115+
})
1116+
1117+
const dispatchOptions = {
1118+
retryOptions: {
1119+
retry: function (err, _, done) {
1120+
counter++
1121+
1122+
if (err.code && err.code === 'UND_ERR_DESTROYED') {
1123+
return done(false)
1124+
}
1125+
1126+
if (err.statusCode === 206) return done(err)
1127+
1128+
setTimeout(done, 800)
1129+
},
1130+
ifMatch: false
1131+
},
1132+
method: 'GET',
1133+
path: '/',
1134+
headers: {
1135+
'content-type': 'application/json'
1136+
}
1137+
}
1138+
1139+
server.listen(0, () => {
1140+
const client = new Client(`http://localhost:${server.address().port}`)
1141+
const handler = new RetryHandler(dispatchOptions, {
1142+
dispatch: (...args) => {
1143+
return client.dispatch(...args)
1144+
},
1145+
handler: {
1146+
onRequestSent () {
1147+
t.ok(true, 'pass')
1148+
},
1149+
onConnect () {
1150+
t.ok(true, 'pass')
1151+
},
1152+
onBodySent () {
1153+
t.ok(true, 'pass')
1154+
},
1155+
onHeaders (status, _rawHeaders, resume, _statusMessage) {
1156+
t.strictEqual(status, 200)
1157+
return true
1158+
},
1159+
onData (chunk) {
1160+
chunks.push(chunk)
1161+
return true
1162+
},
1163+
onComplete () {
1164+
t.strictEqual(Buffer.concat(chunks).toString('utf-8'), 'abcdef')
1165+
t.strictEqual(counter, 1)
1166+
},
1167+
onError () {
1168+
t.fail()
1169+
}
1170+
}
1171+
})
1172+
1173+
client.dispatch(
1174+
{
1175+
method: 'GET',
1176+
path: '/',
1177+
headers: {
1178+
'content-type': 'application/json',
1179+
Range: 'bytes=0-3'
1180+
}
1181+
},
1182+
handler
1183+
)
1184+
1185+
after(async () => {
1186+
await client.close()
1187+
1188+
server.close()
1189+
await once(server, 'close')
1190+
})
1191+
})
1192+
1193+
await t.completed
1194+
})
1195+
10891196
test('Issue#3128 - Should ignore weak etags', async t => {
10901197
t = tspl(t, { plan: 9 })
10911198

@@ -1192,7 +1299,7 @@ test('Issue#3128 - Should ignore weak etags', async t => {
11921299
await t.completed
11931300
})
11941301

1195-
test('Weak etags are ignored on range-requests', { only: true }, async t => {
1302+
test('Weak etags are ignored on range-requests', async t => {
11961303
t = tspl(t, { plan: 9 })
11971304

11981305
const chunks = []

0 commit comments

Comments
 (0)