Files
Strix/pkg/tester/source_http.go
T
eduard256 4880e1ad14 Add 15s timeout for HTTP handler requests
Cameras under load may accept TCP connection but never respond,
hanging tester workers indefinitely. Context timeout on the HTTP
request ensures workers are released.
2026-04-03 19:26:17 +00:00

76 lines
1.8 KiB
Go

package tester
import (
"context"
"errors"
"fmt"
"net/http"
"strings"
"time"
"github.com/AlexxIT/go2rtc/pkg/core"
"github.com/AlexxIT/go2rtc/pkg/hls"
"github.com/AlexxIT/go2rtc/pkg/image"
"github.com/AlexxIT/go2rtc/pkg/magic"
"github.com/AlexxIT/go2rtc/pkg/mpjpeg"
"github.com/AlexxIT/go2rtc/pkg/tcp"
)
func init() {
RegisterSource("http", httpHandler)
RegisterSource("https", httpHandler)
RegisterSource("httpx", httpHandler)
}
// httpHandler -- HTTP GET with content-type detection.
// Supports JPEG snapshots, MJPEG streams, HLS, MPEG-TS, and auto-detect via magic.Open.
// Uses go2rtc tcp.Do for Basic + Digest auth and TLS handling.
// ex. "http://admin:pass@192.168.1.100/cgi-bin/snapshot.cgi"
func httpHandler(rawURL string) (core.Producer, error) {
rawURL, _, _ = strings.Cut(rawURL, "#")
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
req, err := http.NewRequestWithContext(ctx, "GET", rawURL, nil)
if err != nil {
cancel()
return nil, fmt.Errorf("http: request: %w", err)
}
res, err := tcp.Do(req)
if err != nil {
cancel()
return nil, fmt.Errorf("http: dial: %w", err)
}
if res.StatusCode != http.StatusOK {
cancel()
tcp.Close(res)
return nil, errors.New("http: " + res.Status)
}
// cancel on success is not called -- context expires naturally,
// connection lifetime is managed by prod.Stop()
ct := res.Header.Get("Content-Type")
if i := strings.IndexByte(ct, ';'); i > 0 {
ct = ct[:i]
}
var ext string
if i := strings.LastIndexByte(req.URL.Path, '.'); i > 0 {
ext = req.URL.Path[i+1:]
}
switch {
case ct == "application/vnd.apple.mpegurl" || ext == "m3u8":
return hls.OpenURL(req.URL, res.Body)
case ct == "image/jpeg":
return image.Open(res)
case ct == "multipart/x-mixed-replace":
return mpjpeg.Open(res.Body)
}
return magic.Open(res.Body)
}