diff --git a/services/dashboard/backend/routes/api.py b/services/dashboard/backend/routes/api.py
index c585170..ed5e039 100644
--- a/services/dashboard/backend/routes/api.py
+++ b/services/dashboard/backend/routes/api.py
@@ -1765,7 +1765,8 @@ async def browser_signatures() -> dict[str, Any]:
f" countIf(h2_dict_family != '') AS sessions_matched, "
f" countIf(tls_h2_family_mismatch > 0) AS sessions_mismatch, "
f" round(100.0 * countIf(h2_dict_family != '') / greatest(countIf(h2_settings_known > 0), 1), 1) AS match_rate, "
- f" round(100.0 * countIf(tls_h2_family_mismatch > 0) / greatest(countIf(h2_settings_known > 0), 1), 1) AS mismatch_rate "
+ f" round(100.0 * countIf(tls_h2_family_mismatch > 0) / greatest(countIf(h2_settings_known > 0), 1), 1) AS mismatch_rate, "
+ f" countIf(h2_priority_present > 0) AS sessions_with_priority "
f"FROM {_DB}.view_ai_features_1h"
)
if stats:
@@ -1829,7 +1830,14 @@ async def browser_signatures() -> dict[str, Any]:
f" h2_window_update_value AS wu_value, "
f" hits, "
f" h2_pseudo_ord_raw AS pseudo_order, "
- f" fingerprint_coherence_score AS coherence "
+ f" fingerprint_coherence_score AS coherence, "
+ f" h2_header_table_size, "
+ f" h2_enable_push, "
+ f" h2_max_concurrent_streams, "
+ f" h2_initial_window_size, "
+ f" h2_max_frame_size, "
+ f" h2_max_header_list_size, "
+ f" h2_enable_connect_protocol "
f"FROM {_DB}.view_ai_features_1h "
f"WHERE tls_h2_family_mismatch > 0 "
f"ORDER BY hits DESC "
diff --git a/services/dashboard/backend/templates/browsers.html b/services/dashboard/backend/templates/browsers.html
index 3b8e499..590bcb1 100644
--- a/services/dashboard/backend/templates/browsers.html
+++ b/services/dashboard/backend/templates/browsers.html
@@ -156,6 +156,7 @@
IP |
JA4 famille |
H2 famille |
+ SETTINGS |
WU value |
Pseudo-order |
Hits |
@@ -163,7 +164,7 @@
- | Chargement… |
+ | Chargement… |
@@ -525,8 +526,8 @@ async function loadBrowserData() {
setText('pseudo-chromesafari', fmt(chrome + safari));
setText('pseudo-firefox', fmt(firefox));
setText('pseudo-other', fmt(other));
- // Pour h2_priority_present on n'a pas le chiffre direct — afficher N/A
- setText('pseudo-priority', '—');
+ // Pour h2_priority_present on utilise le compteur direct de l'API
+ setText('pseudo-priority', fmt(s.sessions_with_priority));
}
// ─── Graphiques ──────────────────────────────────────────────────────────
@@ -605,7 +606,7 @@ function renderMismatchBar(rows) {
function renderSuspects(rows) {
const tbody = document.getElementById('tbl-suspects-body');
if (!rows.length) {
- tbody.innerHTML = '| Aucun mismatch détecté dans les 24 dernières heures |
';
+ tbody.innerHTML = '| Aucun mismatch détecté dans les 24 dernières heures |
';
return;
}
const WU_LABELS = {
@@ -615,6 +616,23 @@ function renderSuspects(rows) {
1073676289: 'go net/http',
0: 'absent',
};
+ // Noms courts des paramètres SETTINGS (ID → label)
+ const SETTINGS_NAMES = {
+ h2_header_table_size: '1',
+ h2_enable_push: '2',
+ h2_max_concurrent_streams: '3',
+ h2_initial_window_size: '4',
+ h2_max_frame_size: '5',
+ h2_max_header_list_size: '6',
+ h2_enable_connect_protocol: '8',
+ };
+ function fmtSettings(r) {
+ const pairs = Object.entries(SETTINGS_NAMES)
+ .filter(([col]) => r[col] != null && r[col] !== -1)
+ .map(([col, id]) => `${id}:${r[col]}`);
+ if (!pairs.length) return '—';
+ return `${escHtml(pairs.join(', '))}`;
+ }
tbody.innerHTML = rows.map(r => {
const wuLabel = WU_LABELS[r.wu_value] || `${r.wu_value}`;
const coh = r.coherence != null ? r.coherence.toFixed(2) : '—';
@@ -624,6 +642,7 @@ function renderSuspects(rows) {
${r.ip} |
${r.ja4_family || '—'} |
${h2fam} |
+ ${fmtSettings(r)} |
${wuLabel} |
${r.pseudo_order || '—'} |
${fmt(r.hits)} |