Files
goget/cmd/goget/setup.go
T

266 lines
6.7 KiB
Go

//go:build linux || freebsd
// +build linux freebsd
package main
import (
"fmt"
stdhttp "net/http"
"net/url"
"os"
"strconv"
"strings"
"time"
"codeberg.org/petrbalvin/goget/internal/auth"
"codeberg.org/petrbalvin/goget/internal/cli"
"codeberg.org/petrbalvin/goget/internal/config"
"codeberg.org/petrbalvin/goget/internal/cookie"
"codeberg.org/petrbalvin/goget/internal/core"
"codeberg.org/petrbalvin/goget/internal/protocol/http"
"codeberg.org/petrbalvin/goget/internal/transport"
)
// ApplyFlags populates the Config from CLI flags, global config, and cookie jar.
// It is the single function that maps all CLI flags to config fields — adding a
// new flag only requires adding one block here instead of hunting through
// scattered setup code.
func ApplyFlags(c *http.Config, f *Flags, cfg *config.Config, cookieJar *cookie.Jar, parsedURL *url.URL) {
// ── Transport defaults from global config ──
c.Transport.Timeout = cfg.GetEffectiveTimeout(-1, *f.Timeout)
c.Transport.Dialer.IPv4Fallback = cfg.IPv4Fallback
c.Transport.Dialer.Debug = cfg.Debug
c.UserAgent = cfg.UserAgent
c.Output.Verbose = cfg.Verbose
c.Parallel = &core.ParallelConfig{
Connections: cfg.GetParallelConnections(-1),
MinSize: 100 * 1024 * 1024,
MinChunkSize: 5 * 1024 * 1024,
MaxChunkSize: 50 * 1024 * 1024,
}
if cfg.MaxSpeed > 0 {
c.RateLimiter = transport.NewTokenBucket(cfg.MaxSpeed, cfg.MaxSpeed/10)
}
// ── DNS / interface ──
if len(cfg.DNSServers) > 0 {
c.Transport.DNSServers = cfg.DNSServers
}
if *f.BindInterface != "" {
c.Transport.BindInterface = *f.BindInterface
}
c.Transport.BlockPrivateIPs = !*f.AllowPrivate
// ── Authentication ──
if cfg.Auth.Username == "" && cfg.Auth.OAuth.AccessToken == "" {
if user, pass, ok := auth.LookupNetrc(parsedURL.Hostname()); ok {
cfg.Auth.Username = user
cfg.Auth.Password = pass
}
}
if cfg.Auth.Username != "" || cfg.Auth.OAuth.AccessToken != "" {
c.Auth.Username = cfg.Auth.Username
c.Auth.Password = cfg.Auth.Password
c.Auth.AuthType = cfg.Auth.AuthType
c.Auth.OAuth = &cfg.Auth.OAuth
}
if cookieJar != nil {
c.CookieJar = cookieJar
}
// ── TLS and certificates ──
if *f.Insecure && c.Transport.TLS != nil {
c.Transport.TLS.InsecureSkipVerify = true
}
if *f.CertFile != "" && c.Transport.TLS != nil {
c.Transport.TLS.CertFile = *f.CertFile
}
if *f.KeyFile != "" && c.Transport.TLS != nil {
c.Transport.TLS.KeyFile = *f.KeyFile
}
if *f.PinnedCert != "" && c.Transport.TLS != nil {
c.Transport.TLS.PinnedCertHash = *f.PinnedCert
}
if *f.CACertificate != "" && c.Transport.TLS != nil {
c.Transport.TLS.CACertFile = *f.CACertificate
}
if *f.SSLKeyLogFile != "" && c.Transport.TLS != nil {
c.Transport.TLS.KeyLogFile = *f.SSLKeyLogFile
}
if *f.ConnectTimeout > 0 && c.Transport.Dialer != nil {
c.Transport.Dialer.Timeout = *f.ConnectTimeout
}
// ── Retry and redirects ──
if *f.NoRedirect {
c.Transport.FollowRedirects = false
}
if *f.MaxRetries > 0 {
c.Transport.MaxRetries = *f.MaxRetries
if c.Transport.Retry != nil {
c.Transport.Retry.MaxRetries = *f.MaxRetries
}
}
if *f.RetryDelay > 0 {
c.Transport.RetryDelay = *f.RetryDelay
}
if *f.RetryHTTPError != "" {
for _, code := range strings.Split(*f.RetryHTTPError, ",") {
if code, err := strconv.Atoi(strings.TrimSpace(code)); err == nil {
c.Transport.RetryHTTPCodes = append(c.Transport.RetryHTTPCodes, code)
}
}
}
if *f.RetryAllErrors {
c.Transport.RetryAllErrors = true
}
// ── Timeouts and limits ──
if *f.ConnectTimeout > 0 {
c.Transport.ConnectTimeout = *f.ConnectTimeout
}
if *f.MaxTime > 0 {
c.Transport.MaxTime = *f.MaxTime
}
if *f.MaxFileSize != "" {
size, perr := parseRateLimit(*f.MaxFileSize)
if perr != nil {
cli.PrintWarning(os.Stderr, fmt.Sprintf("ignoring --max-filesize: %v; size limit disabled", perr))
}
c.Transport.MaxFileSize = size
}
// ── Output flags ──
if *f.ContentDisp {
c.Output.ContentDisposition = true
}
if *f.ShowHeaders {
c.Output.ShowHeaders = true
}
if *f.KeepTimestamps {
c.Output.KeepTimestamps = true
}
if *f.JSON {
c.Output.JSONOutput = true
}
if *f.OnComplete != "" {
c.Output.OnComplete = *f.OnComplete
}
if *f.WarcFile != "" {
c.Output.WarcFile = *f.WarcFile
}
if *f.TraceTime {
c.Output.TraceTime = true
}
if *f.WriteOut != "" {
c.Output.WriteOut = *f.WriteOut
}
// ── Request flags ──
if len(f.Headers) > 0 {
if c.CustomHeaders == nil {
c.CustomHeaders = make(map[string]string)
}
for _, h := range f.Headers {
parts := strings.SplitN(h, ":", 2)
key := strings.TrimSpace(parts[0])
val := ""
if len(parts) > 1 {
val = strings.TrimSpace(parts[1])
}
if strings.ContainsAny(key, "\r\n") || strings.ContainsAny(val, "\r\n") {
cli.PrintWarning(os.Stderr, fmt.Sprintf("Skipping header with CRLF: %s", key))
continue
}
c.CustomHeaders[key] = val
}
}
if *f.Data != "" {
c.PostData = *f.Data
}
if *f.PostFile != "" {
c.PostFile = *f.PostFile
}
if *f.Range != "" {
c.Range = *f.Range
}
if *f.Compressed {
c.Compressed = true
}
if *f.Referer != "" {
c.Referer = *f.Referer
}
if *f.Fail {
c.FailOnHTTPError = true
}
if *f.NoClobber {
c.Transport.NoClobber = true
}
if len(f.Form) > 0 {
c.FormData = f.Form
}
// ── Recursive flags ──
if *f.RecursiveParallel > 0 {
c.Recursive.Parallel = *f.RecursiveParallel
}
if *f.Wait != "" {
if d, err := time.ParseDuration(*f.Wait); err == nil {
c.Recursive.Wait = d
}
}
if *f.RandomWait {
c.Recursive.RandomWait = true
}
if *f.ConvertLinks {
c.Recursive.ConvertLinks = true
}
if *f.Accept != "" {
c.Recursive.Accept = *f.Accept
}
if *f.Domains != "" {
c.Recursive.Domains = strings.Split(*f.Domains, ",")
}
if *f.Reject != "" {
c.Recursive.Reject = strings.Split(*f.Reject, ",")
}
if *f.CutDirs > 0 {
c.Recursive.CutDirs = *f.CutDirs
}
if *f.PageRequisites {
c.Recursive.PageRequisites = true
}
if *f.SpanHosts {
c.Recursive.SpanHosts = true
}
if *f.AdjustExt {
c.Recursive.AdjustExt = true
}
if *f.BackupConverted {
c.Recursive.BackupConverted = true
}
// ── Cookies from CLI flags ──
if len(f.Cookies) > 0 {
if cookieJar == nil {
var err error
cookieJar, err = cookie.NewJar()
if err != nil {
cli.PrintWarning(os.Stderr, fmt.Sprintf("failed to create cookie jar: %v", err))
}
}
if cookieJar != nil {
for _, cstr := range f.Cookies {
parts := strings.SplitN(cstr, "=", 2)
if len(parts) < 2 {
cli.PrintWarning(os.Stderr, fmt.Sprintf("invalid cookie format (use name=value): %s", cstr))
continue
}
ck := &stdhttp.Cookie{Name: parts[0], Value: parts[1]}
cookieJar.SetCookies(parsedURL, []*stdhttp.Cookie{ck})
}
c.CookieJar = cookieJar
}
}
}