feat: initial goget release — modern IPv6-first download utility

This commit is contained in:
2026-06-26 21:21:58 +02:00
commit 53db81e1f7
147 changed files with 45931 additions and 0 deletions
+105
View File
@@ -0,0 +1,105 @@
//go:build linux || freebsd
// +build linux freebsd
package dataurl
import (
"context"
"encoding/base64"
"io"
"net/url"
"os"
"strings"
"time"
"codeberg.org/petrbalvin/goget/internal/core"
"codeberg.org/petrbalvin/goget/internal/protocol"
)
// Protocol handles data: URLs (RFC 2397).
type Protocol struct {
*protocol.BaseProtocol
}
// NewProtocol creates a new data: URL protocol handler.
func NewProtocol() *Protocol {
return &Protocol{
BaseProtocol: protocol.NewBaseProtocol(protocol.ProtocolInfo{
Name: "DATA",
Scheme: "data",
DefaultPort: 0,
Features: []string{},
}),
}
}
func (p *Protocol) Download(ctx context.Context, req *core.DownloadRequest) (*core.DownloadResult, error) {
startTime := time.Now()
// data:[<mediatype>][;base64],<data>
data, err := Decode(req.URL.String())
if err != nil {
return nil, core.NewProtocolError("failed to decode data URL", err, core.SafeURL(req.URL))
}
var writer io.Writer
outputPath := req.Output
if req.Writer != nil {
writer = req.Writer
} else if outputPath == "" || outputPath == "-" {
writer = os.Stdout
outputPath = "-"
} else {
f, err := os.Create(outputPath)
if err != nil {
return nil, core.NewFileError("failed to create output file", err)
}
defer f.Close()
writer = f
}
n, err := writer.Write(data)
if err != nil {
return nil, core.NewFileError("failed to write data URL content", err)
}
duration := time.Since(startTime)
return &core.DownloadResult{
BytesDownloaded: int64(n),
TotalSize: int64(len(data)),
Duration: duration,
Protocol: "DATA",
IPVersion: 0,
Speed: float64(n) / duration.Seconds(),
OutputPath: outputPath,
}, nil
}
// Decode parses and decodes a data: URL.
func Decode(rawURL string) ([]byte, error) {
if !strings.HasPrefix(rawURL, "data:") {
return nil, nil
}
content := strings.TrimPrefix(rawURL, "data:")
isBase64 := false
if idx := strings.Index(content, ";base64,"); idx >= 0 {
isBase64 = true
content = content[idx+8:]
} else if idx := strings.Index(content, ","); idx >= 0 {
content = content[idx+1:]
}
decoded, err := url.PathUnescape(content)
if err != nil {
decoded = content
}
if isBase64 {
return base64.StdEncoding.DecodeString(decoded)
}
return []byte(decoded), nil
}
+93
View File
@@ -0,0 +1,93 @@
//go:build linux || freebsd
// +build linux freebsd
package dataurl
import (
"bytes"
"context"
"net/url"
"os"
"path/filepath"
"testing"
"codeberg.org/petrbalvin/goget/internal/core"
)
func TestDecodePlainText(t *testing.T) {
data, err := Decode("data:text/plain,hello%20world")
if err != nil {
t.Fatal(err)
}
if string(data) != "hello world" {
t.Errorf("got %q, want %q", data, "hello world")
}
}
func TestDecodeBase64(t *testing.T) {
data, err := Decode("data:text/plain;base64,SGVsbG8=")
if err != nil {
t.Fatal(err)
}
if string(data) != "Hello" {
t.Errorf("got %q, want %q", data, "Hello")
}
}
func TestDecodeEmpty(t *testing.T) {
data, err := Decode("data:,")
if err != nil {
t.Fatal(err)
}
if len(data) != 0 {
t.Errorf("expected empty, got %d bytes", len(data))
}
}
func TestDecodeNotDataURL(t *testing.T) {
data, err := Decode("https://example.com")
if err != nil {
t.Fatal(err)
}
if data != nil {
t.Error("expected nil for non-data URL")
}
}
func TestDownloadPlainText(t *testing.T) {
var buf bytes.Buffer
proto := NewProtocol()
u, _ := url.Parse("data:text/plain,test123")
result, err := proto.Download(context.Background(), &core.DownloadRequest{
URL: u,
Writer: &buf,
})
if err != nil {
t.Fatal(err)
}
if result.BytesDownloaded != 7 {
t.Errorf("bytes = %d, want 7", result.BytesDownloaded)
}
if buf.String() != "test123" {
t.Errorf("got %q, want %q", buf.String(), "test123")
}
}
func TestDownloadToFile(t *testing.T) {
tmp := t.TempDir()
dst := filepath.Join(tmp, "out.txt")
proto := NewProtocol()
u, _ := url.Parse("data:text/plain,hello")
_, err := proto.Download(context.Background(), &core.DownloadRequest{
URL: u,
Output: dst,
})
if err != nil {
t.Fatal(err)
}
data, _ := os.ReadFile(dst)
if string(data) != "hello" {
t.Errorf("got %q, want %q", data, "hello")
}
}