github.com/letsencrypt/boulder@v0.20251208.0/observer/probers/http/http.go (about) 1 package probers 2 3 import ( 4 "context" 5 "crypto/tls" 6 "fmt" 7 "net/http" 8 "slices" 9 "time" 10 11 "github.com/letsencrypt/boulder/observer/obsdialer" 12 ) 13 14 // HTTPProbe is the exported 'Prober' object for monitors configured to 15 // perform HTTP requests. 16 type HTTPProbe struct { 17 url string 18 rcodes []int 19 useragent string 20 insecure bool 21 } 22 23 // Name returns a string that uniquely identifies the monitor. 24 25 func (p HTTPProbe) Name() string { 26 insecure := "" 27 if p.insecure { 28 insecure = "-insecure" 29 } 30 return fmt.Sprintf("%s-%d-%s%s", p.url, p.rcodes, p.useragent, insecure) 31 } 32 33 // Kind returns a name that uniquely identifies the `Kind` of `Prober`. 34 func (p HTTPProbe) Kind() string { 35 return "HTTP" 36 } 37 38 // isExpected ensures that the received HTTP response code matches one 39 // that's expected. 40 func (p HTTPProbe) isExpected(received int) bool { 41 return slices.Contains(p.rcodes, received) 42 } 43 44 // Probe performs the configured HTTP request. 45 func (p HTTPProbe) Probe(timeout time.Duration) (bool, time.Duration) { 46 ctx, cancel := context.WithTimeout(context.Background(), timeout) 47 defer cancel() 48 client := http.Client{ 49 Transport: &http.Transport{ 50 TLSClientConfig: &tls.Config{InsecureSkipVerify: p.insecure}, 51 DialContext: obsdialer.Dialer.DialContext, 52 }} 53 req, err := http.NewRequestWithContext(ctx, "GET", p.url, nil) 54 if err != nil { 55 return false, 0 56 } 57 req.Header.Set("User-Agent", p.useragent) 58 start := time.Now() 59 // TODO(@beautifulentropy): add support for more than HTTP GET 60 resp, err := client.Do(req) 61 if err != nil { 62 return false, time.Since(start) 63 } 64 return p.isExpected(resp.StatusCode), time.Since(start) 65 }