Skip to content

Commit 314a737

Browse files
committed
feat: HTTP 协议版本改走 webRequest statusLine
之前 HTTP/2 / HTTP/3 仅靠注入脚本读 PerformanceResourceTiming.nextHopProtocol,但跨域资源没有 Timing-Allow-Origin 时浏览器会把 nextHopProtocol 置空(abs.twimg.com 等典型情况),同时还要等资源完成加载,时序不稳定。改成在 service worker 的 webRequest.onHeadersReceived 里从 statusLine 正则提取 HTTP/<version>,存到 headerRecord.httpProtocol,再在 popup 合并阶段扫主请求 / API / iframe 三处记录汇总。注入脚本的 nextHopProtocol 兜底保留,两路一起命中合并不变。 将版本号提升到 1.3.44。
1 parent a4fed80 commit 314a737

3 files changed

Lines changed: 58 additions & 1 deletion

File tree

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "stackprism",
33
"private": true,
4-
"version": "1.3.43",
4+
"version": "1.3.44",
55
"type": "module",
66
"description": "StackPrism 用于检测网页前端、后端、CDN、SaaS、广告营销、统计、登录、支付、网站程序和主题模板线索。",
77
"scripts": {

src/background/headers.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,13 @@ const sanitizeAllHeaders = (headers: Record<string, string>) => {
240240
return out
241241
}
242242

243+
// 从 webRequest 的 statusLine 拿协议版本 — "HTTP/2 200" / "HTTP/3 200" 这种
244+
// 比 PerformanceResourceTiming.nextHopProtocol 可靠:不需要 Timing-Allow-Origin,请求时刻就拿到
245+
const extractHttpProtocol = (statusLine: unknown): string => {
246+
const match = /^HTTP\/([0-9.]+)/i.exec(String(statusLine || ''))
247+
return match ? match[1].toLowerCase() : ''
248+
}
249+
243250
export const buildHeaderRecord = (details: any, headerRules: any, settings: any) => {
244251
const normalizedHeaders = normalizeHeaders(details.responseHeaders)
245252
const headers = pickHeaders(normalizedHeaders, headerRules.interestingHeaders || [])
@@ -249,6 +256,7 @@ export const buildHeaderRecord = (details: any, headerRules: any, settings: any)
249256
type: details.type,
250257
method: details.method,
251258
statusCode: details.statusCode,
259+
httpProtocol: extractHttpProtocol(details.statusLine),
252260
time: Date.now(),
253261
headers,
254262
allHeaders: sanitizeAllHeaders(normalizedHeaders),

src/background/popup-cache.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,10 +267,59 @@ const suppressSelfHostTechs = (technologies: any[], pageUrl: string, suppressMap
267267
return technologies.filter(tech => !suppressNames.has(String(tech?.name || '')))
268268
}
269269

270+
// 从所有 webRequest 记录里收集 HTTP 协议版本,比注入脚本里读 PerformanceResourceTiming.nextHopProtocol
271+
// 可靠得多——跨域资源没有 Timing-Allow-Origin 时浏览器把 nextHopProtocol 置空,而 statusLine 是请求发起时浏览器自己写的
272+
const collectHttpProtocolTechs = (data: any): any[] => {
273+
const protocols = new Set<string>()
274+
const sampleByProto = new Map<string, string>()
275+
const consume = (record: any) => {
276+
const proto = String(record?.httpProtocol || '').toLowerCase()
277+
if (!proto) return
278+
protocols.add(proto)
279+
if (!sampleByProto.has(proto)) sampleByProto.set(proto, String(record?.url || ''))
280+
}
281+
consume(data?.main)
282+
for (const api of data?.apis || []) consume(api)
283+
for (const frame of data?.frames || []) consume(frame)
284+
const out: any[] = []
285+
const has3 = ['3', '3.0', 'h3'].some(v => protocols.has(v))
286+
const has2 = ['2', '2.0', 'h2', 'h2c'].some(v => protocols.has(v))
287+
if (has3) {
288+
out.push({
289+
category: '安全与协议',
290+
name: 'HTTP/3',
291+
confidence: '高',
292+
evidence: [`资源使用 HTTP/3 协议(如 ${shortHostFromUrl(sampleByProto.get('3') || sampleByProto.get('h3') || '')})`],
293+
source: '响应头'
294+
})
295+
}
296+
if (has2) {
297+
out.push({
298+
category: '安全与协议',
299+
name: 'HTTP/2',
300+
confidence: '高',
301+
evidence: [
302+
`资源使用 HTTP/2 协议(如 ${shortHostFromUrl(sampleByProto.get('2') || sampleByProto.get('2.0') || sampleByProto.get('h2') || '')})`
303+
],
304+
source: '响应头'
305+
})
306+
}
307+
return out
308+
}
309+
310+
const shortHostFromUrl = (url: string): string => {
311+
try {
312+
return new URL(url).host || url
313+
} catch {
314+
return url
315+
}
316+
}
317+
270318
const buildDisplayTechnologies = (data: any, settings: any, suppressMap: Record<string, string[]>) => {
271319
const all: any[] = []
272320
addAllTechnologies(all, data.page?.technologies)
273321
addAllTechnologies(all, data.main?.technologies)
322+
addAllTechnologies(all, collectHttpProtocolTechs(data))
274323
for (const api of data.apis || []) {
275324
addAllTechnologies(
276325
all,

0 commit comments

Comments
 (0)