checker-matrix/checker/collect.go
Pierre-Olivier Mercier 2af16d3ab9 checker: harden HTTP collection and stabilize report ordering
Validate the federation tester URI placeholder, escape the domain, set
a client timeout, cap the response body, and ship CA certificates in
the scratch image so HTTPS calls succeed. Sort hosts, connection
reports, and errors when rendering so output is deterministic, and
deduplicate TLS problems. Drop the deprecated aggregate Rule() and add
tests for collection and rules.
2026-04-26 04:13:55 +07:00

62 lines
1.7 KiB
Go

package checker
import (
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"net/url"
"strings"
"time"
sdk "git.happydns.org/checker-sdk-go/checker"
)
const (
defaultTesterURI = "https://federationtester.matrix.org/api/report?server_name=%s"
collectHTTPTimeout = 30 * time.Second
maxResponseBodySize = 5 << 20 // 5 MiB
)
var collectHTTPClient = &http.Client{Timeout: collectHTTPTimeout}
func (p *matrixProvider) Collect(ctx context.Context, opts sdk.CheckerOptions) (any, error) {
domain, _ := opts["serviceDomain"].(string)
if domain == "" {
return nil, fmt.Errorf("serviceDomain is required")
}
domain = strings.TrimSuffix(domain, ".")
testerURI, _ := opts["federationTesterServer"].(string)
if testerURI == "" {
testerURI = defaultTesterURI
}
if !strings.Contains(testerURI, "%s") {
return nil, fmt.Errorf("federationTesterServer must contain a %%s placeholder for the domain")
}
reqURL := fmt.Sprintf(testerURI, url.QueryEscape(domain))
req, err := http.NewRequestWithContext(ctx, http.MethodGet, reqURL, nil)
if err != nil {
return nil, fmt.Errorf("unable to build the request: %w", err)
}
resp, err := collectHTTPClient.Do(req)
if err != nil {
return nil, fmt.Errorf("unable to perform the test: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode >= 300 {
return nil, fmt.Errorf("federation tester returned status %d; check https://federationtester.matrix.org/#%s", resp.StatusCode, domain)
}
var data MatrixFederationData
if err := json.NewDecoder(io.LimitReader(resp.Body, maxResponseBodySize)).Decode(&data); err != nil {
return nil, fmt.Errorf("failed to decode federation tester response: %w", err)
}
return &data, nil
}