fix(sub): bound what one subscription response renders

A subscription's size is the product of its clients and inbounds with
each one's remark and endpoints, and nothing bounded that product: data
adopted from a node could make one unauthenticated request render
gigabytes and run the panel out of memory.

Each request now carries an 8 MiB budget that the raw, JSON and Clash
outputs charge as they materialize a client's links, configs or
proxies. Rendering stops once it is spent, with one warning, and
anything below the budget is unchanged.
This commit is contained in:
MHSanaei
2026-11-01 01:15:28 +01:00
parent fc8efc0745
commit 2467b9d542
5 changed files with 161 additions and 6 deletions
+2 -2
View File
@@ -173,7 +173,7 @@ func (s *SubJsonService) GetJson(subId string, host string, alwaysReturnArray bo
hasBoundClosed = hasBoundClosed || closed
for _, variant := range variants {
render := func() subConfigEntry {
configs := s.getConfig(subReq, variant.inbound(subReq, inbound), client, host)
configs := s.budgetedConfig(subReq, variant.inbound(subReq, inbound), client, host)
return subConfigEntry{sortIndex: inbound.SubSortIndex, id: inbound.Id, configs: configs, hostOrder: variant.order}
}
ordered = append(ordered, orderedSubEntry[func() subConfigEntry]{variant.order, render})
@@ -191,7 +191,7 @@ func (s *SubJsonService) GetJson(subId string, host string, alwaysReturnArray bo
injectExternalProxy(&clone, effectiveEps)
effective = &clone
}
inboundConfigs = append(inboundConfigs, s.getConfig(subReq, effective, client, host)...)
inboundConfigs = append(inboundConfigs, s.budgetedConfig(subReq, effective, client, host)...)
}
if len(inboundConfigs) > 0 {
entries = append(entries, subConfigEntry{