This document explains how goget processes a download request from start to finish — the phase structure, parallel chunking, resume logic, and output writing.
The `internal/output` package creates an atomic writer:
1.**Temp file** — Writes to `<filename>.goget.tmp` during download
2.**Parent directories** — If `--create-dirs` is enabled (default: `true`), missing parent directories are created via `os.MkdirAll` before opening the output file. Pass `--create-dirs=false` to restore strict behaviour
3.**Resume metadata** — Reads `<filename>.goget.meta` if resuming
4.**Progress callback** — Hooks into the writer for real-time speed/ETA
The decrypted file replaces the encrypted one (`.gpg` → stripped extension, or `.decrypted` suffix).
### HSTS Cache
After every successful HTTPS connection, the HSTS cache (`~/.config/goget/hsts`) is updated per RFC 6797. Expired entries are pruned on load. This ensures that future `http://` requests to known hosts are automatically upgraded to `https://`.
### Graceful Shutdown (SIGINT)
When the user sends Ctrl+C (SIGINT) during a download, goget persists partial progress to the `.goget.meta` sidecar for **all protocols** (HTTP, FTP, SFTP, WebDAV) and exits with code 130. A subsequent `goget --resume` picks up where it left off. The signal handler uses `signal.NotifyContext` and propagates cancellation through the download pipeline via `ctx.Err()` checks after every read.
## Smart Timeout
When no explicit `--timeout` is set, goget calculates a timeout based on file size:
```
timeout = (fileSize / minSpeed) × safetyFactor
```
Where:
-`minSpeed` = 10 KB/s (conservative minimum)
-`safetyFactor` = 3.0
-`minTimeout` = 30 seconds
-`maxTimeout` = 24 hours
A 1 GB file at 10 KB/s → 34 hours (capped to 24 hours max).
A 10 MB file at 10 KB/s → 51 minutes.
## Rate Limiting
`--rate-limit` uses a token bucket algorithm:
```go
bucket:=transport.NewTokenBucket(rate)
// For each read:
bucket.Wait(n)
```
The token bucket allows short bursts above the limit while maintaining the average rate.
### Speed Format
```
--rate-limit 1MB/s # 1,000,000 bytes/sec
--rate-limit 500KB/s # 500,000 bytes/sec
--rate-limit 1GB/s # 1,000,000,000 bytes/sec
--rate-limit 100 # 100 bytes/sec (plain number)
```
## Retry Logic
When a download fails, goget retries with exponential backoff:
```
Attempt 1: wait 1s, retry
Attempt 2: wait 2s, retry
Attempt 3: wait 4s, retry
...
Attempt N: wait min(2^(N-1) × 1s, 30s), retry
```
Max retries default to 3. Use `--max-retries N` to increase. Use `--retry-all-errors` to retry on HTTP 4xx/5xx (by default, only 5xx server errors trigger retries).