mirror of
https://github.com/gotenberg/gotenberg.git
synced 2026-08-08 16:42:15 +01:00
122 lines
2.9 KiB
Go
122 lines
2.9 KiB
Go
package chromium
|
|
|
|
import (
|
|
"net/url"
|
|
"sync"
|
|
|
|
"github.com/chromedp/cdproto/network"
|
|
)
|
|
|
|
// maxTrackedOrigins bounds the distinct origins kept per conversion so a
|
|
// pathological page cannot grow the set without limit.
|
|
const maxTrackedOrigins = 64
|
|
|
|
// networkAggregate accumulates per-conversion network activity from Chromium
|
|
// DevTools events. It is safe for concurrent use by the chromedp event listener
|
|
// goroutine and the conversion goroutine that reads the snapshot afterwards.
|
|
type networkAggregate struct {
|
|
mu sync.Mutex
|
|
|
|
requestCount int64
|
|
bytesTotal int64
|
|
failedCount int64
|
|
|
|
origins map[string]struct{}
|
|
requestURLByID map[network.RequestID]string
|
|
|
|
heaviestURL string
|
|
heaviestBytes int64
|
|
}
|
|
|
|
// networkStats is an immutable snapshot of a [networkAggregate].
|
|
type networkStats struct {
|
|
requestCount int64
|
|
bytesTotal int64
|
|
failedCount int64
|
|
uniqueOrigins int64
|
|
heaviestURL string
|
|
heaviestBytes int64
|
|
}
|
|
|
|
func newNetworkAggregate() *networkAggregate {
|
|
return &networkAggregate{
|
|
origins: make(map[string]struct{}),
|
|
requestURLByID: make(map[network.RequestID]string),
|
|
}
|
|
}
|
|
|
|
// onResponseReceived records the response origin and remembers the URL for the
|
|
// request id, so a later loading-finished event can attribute its bytes.
|
|
func (a *networkAggregate) onResponseReceived(ev *network.EventResponseReceived) {
|
|
if ev == nil || ev.Response == nil {
|
|
return
|
|
}
|
|
|
|
a.mu.Lock()
|
|
defer a.mu.Unlock()
|
|
|
|
if origin := originOf(ev.Response.URL); origin != "" {
|
|
if _, ok := a.origins[origin]; !ok && len(a.origins) < maxTrackedOrigins {
|
|
a.origins[origin] = struct{}{}
|
|
}
|
|
}
|
|
a.requestURLByID[ev.RequestID] = ev.Response.URL
|
|
}
|
|
|
|
// onLoadingFinished records a successfully completed request and its size,
|
|
// tracking the single heaviest resource.
|
|
func (a *networkAggregate) onLoadingFinished(ev *network.EventLoadingFinished) {
|
|
if ev == nil {
|
|
return
|
|
}
|
|
|
|
a.mu.Lock()
|
|
defer a.mu.Unlock()
|
|
|
|
a.requestCount++
|
|
|
|
size := int64(ev.EncodedDataLength)
|
|
a.bytesTotal += size
|
|
if size > a.heaviestBytes {
|
|
a.heaviestBytes = size
|
|
a.heaviestURL = a.requestURLByID[ev.RequestID]
|
|
}
|
|
}
|
|
|
|
// onLoadingFailed records a request that failed to complete.
|
|
func (a *networkAggregate) onLoadingFailed(ev *network.EventLoadingFailed) {
|
|
if ev == nil {
|
|
return
|
|
}
|
|
|
|
a.mu.Lock()
|
|
defer a.mu.Unlock()
|
|
|
|
a.requestCount++
|
|
a.failedCount++
|
|
}
|
|
|
|
func (a *networkAggregate) snapshot() networkStats {
|
|
a.mu.Lock()
|
|
defer a.mu.Unlock()
|
|
|
|
return networkStats{
|
|
requestCount: a.requestCount,
|
|
bytesTotal: a.bytesTotal,
|
|
failedCount: a.failedCount,
|
|
uniqueOrigins: int64(len(a.origins)),
|
|
heaviestURL: a.heaviestURL,
|
|
heaviestBytes: a.heaviestBytes,
|
|
}
|
|
}
|
|
|
|
// originOf returns the scheme://host of rawURL, or an empty string when it has
|
|
// no host (for example data: or file: URLs).
|
|
func originOf(rawURL string) string {
|
|
parsed, err := url.Parse(rawURL)
|
|
if err != nil || parsed.Host == "" {
|
|
return ""
|
|
}
|
|
return parsed.Scheme + "://" + parsed.Host
|
|
}
|