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  }