package traefik_rybbit_feeder import ( "bytes" "context" "encoding/json" "fmt" "io" "net" "net/http" "regexp" "strings" "time" ) func sendRequest(ctx context.Context, url string, body interface{}, headers http.Header) (*http.Response, error) { var req *http.Request var err error if body != nil { bodyJson, err := json.Marshal(body) if err != nil { return nil, err } req, err = http.NewRequestWithContext(ctx, http.MethodPost, url, bytes.NewReader(bodyJson)) } else { req, err = http.NewRequestWithContext(ctx, http.MethodGet, url, nil) } if err != nil { return nil, err } if headers != nil { req.Header = headers } if body != nil { req.Header.Set("Content-Type", "application/json") } client := &http.Client{Timeout: 10 * time.Second} resp, err := client.Do(req) if err != nil { return nil, err } status := resp.StatusCode if status < 200 || status >= 300 { defer func() { _ = resp.Body.Close() }() respBody, err := io.ReadAll(resp.Body) if err != nil { return nil, fmt.Errorf("request failed with status %d (failed to read body: %v)", status, err) } return nil, fmt.Errorf("request failed with status %d (%v)", status, string(respBody)) } return resp, nil } func sendRequestAndParse(ctx context.Context, url string, body interface{}, headers http.Header, value interface{}) error { resp, err := sendRequest(ctx, url, body, headers) if err != nil { return err } defer func() { _ = resp.Body.Close() }() respBody, err := io.ReadAll(resp.Body) if err != nil { return err } err = json.Unmarshal(respBody, &value) if err != nil { return err } return nil } func parseDomainFromHost(host string) string { // check if the host has a port if strings.Contains(host, ":") { host = strings.Split(host, ":")[0] } if strings.HasSuffix(host, ".") { host = strings.TrimSuffix(host, ".") } return strings.ToLower(host) } const parseAcceptLanguagePattern = `([a-zA-Z\-]+)(?:;q=\d\.\d)?(?:,\s)?` var parseAcceptLanguageRegexp = regexp.MustCompile(parseAcceptLanguagePattern) func parseAcceptLanguage(acceptLanguage string) string { matches := parseAcceptLanguageRegexp.FindAllStringSubmatch(acceptLanguage, -1) if len(matches) == 0 { return "" } return matches[0][1] } func extractRemoteIP(req *http.Request) string { if ip := req.Header.Get("CF-Connecting-IP"); ip != "" { return ip } if ip := req.Header.Get("x-vercel-ip"); ip != "" { return ip } // Standard proxy headers if xff := req.Header.Get("X-Forwarded-For"); xff != "" { ips := strings.Split(xff, ",") if len(ips) > 0 { return strings.TrimSpace(ips[0]) } } if xrip := req.Header.Get("X-Real-IP"); xrip != "" { return xrip } // Direct connection if req.RemoteAddr != "" { ip, _, err := net.SplitHostPort(req.RemoteAddr) if err == nil { return ip } return req.RemoteAddr } return "" }