package engine import ( "bytes" "context" "errors" "fmt" "io" "net/http" "strings" "sync" "time" "github.com/gost-dom/browser/dom" "github.com/gost-dom/browser/html" gosturl "github.com/gost-dom/browser/url" "github.com/pinchtab/pinchtab/internal/urlutil" nethtml "golang.org/x/net/html" ) var ErrLiteNotSupported = errors.New("operation not supported in lite mode") // liteTab tracks one Gost-DOM window. type liteTab struct { window html.Window url string refMap map[string]dom.Element } // LiteEngine implements Engine using Gost-DOM. type LiteEngine struct { client *http.Client tabs map[string]*liteTab current string // active tab ID seq int // tab ID sequence counter mu sync.Mutex } // NewLiteEngine creates a Gost-DOM based engine. func NewLiteEngine() *LiteEngine { return &LiteEngine{ client: &http.Client{Timeout: 30 * time.Second}, tabs: make(map[string]*liteTab), } } func (l *LiteEngine) Name() string { return "lite" } func (l *LiteEngine) Capabilities() []Capability { return []Capability{CapNavigate, CapSnapshot, CapText, CapClick, CapType} } // Navigate opens a URL in the lite engine and returns the result. func (l *LiteEngine) Navigate(ctx context.Context, url string) (*NavigateResult, error) { l.mu.Lock() defer l.mu.Unlock() // Validate and sanitize URL to prevent SSRF (CodeQL go/request-forgery). safeURL, err := urlutil.Sanitize(url) if err != nil { return nil, fmt.Errorf("lite navigate: %w", err) } // Fetch HTML via HTTP. req, err := http.NewRequestWithContext(ctx, http.MethodGet, safeURL, nil) if err != nil { return nil, fmt.Errorf("lite navigate: %w", err) } req.Header.Set("User-Agent", "Mozilla/5.0 (compatible; PinchTab-Lite/1.0)") req.Header.Set("Accept", "text/html,application/xhtml+xml,*/*") resp, err := l.client.Do(req) if err != nil { return nil, fmt.Errorf("lite navigate fetch: %w", err) } defer func() { _ = resp.Body.Close() }() if resp.StatusCode >= 400 { return nil, fmt.Errorf("lite navigate: HTTP %d from %s", resp.StatusCode, url) } // Detect content type — only process HTML. ct := resp.Header.Get("Content-Type") if ct != "" && !strings.Contains(ct, "html") && !strings.Contains(ct, "xml") { return nil, fmt.Errorf("lite navigate: unsupported content type %q", ct) } // Strip