A vibe coded tangled fork which supports pijul.
1package repo
2
3import (
4 "fmt"
5 "io"
6 "net/http"
7 "net/url"
8 "strings"
9
10 "github.com/go-chi/chi/v5"
11 "tangled.org/core/api/tangled"
12)
13
14func (rp *Repo) DownloadArchive(w http.ResponseWriter, r *http.Request) {
15 l := rp.logger.With("handler", "DownloadArchive")
16 ref := chi.URLParam(r, "ref")
17 ref, _ = url.PathUnescape(ref)
18 ref = strings.TrimSuffix(ref, ".tar.gz")
19 f, err := rp.repoResolver.Resolve(r)
20 if err != nil {
21 l.Error("failed to get repo and knot", "err", err)
22 return
23 }
24
25 // build the xrpc url
26 query := url.Values{}
27 query.Set("repo", f.RepoAt().String())
28 query.Set("ref", ref)
29 query.Set("format", "tar.gz")
30 query.Set("prefix", r.URL.Query().Get("prefix"))
31 xrpcURL := fmt.Sprintf(
32 "%s/xrpc/%s?%s",
33 rp.config.KnotMirror.Url,
34 tangled.GitTempGetArchiveNSID,
35 query.Encode(),
36 )
37
38 // make the get request
39 resp, err := http.Get(xrpcURL)
40 if err != nil {
41 l.Error("failed to call XRPC repo.archive", "err", err)
42 rp.pages.Error503(w)
43 return
44 }
45 defer resp.Body.Close()
46
47 // pass through headers from upstream response
48 if contentDisposition := resp.Header.Get("Content-Disposition"); contentDisposition != "" {
49 w.Header().Set("Content-Disposition", contentDisposition)
50 }
51 if contentType := resp.Header.Get("Content-Type"); contentType != "" {
52 w.Header().Set("Content-Type", contentType)
53 }
54 if contentLength := resp.Header.Get("Content-Length"); contentLength != "" {
55 w.Header().Set("Content-Length", contentLength)
56 }
57 if link := resp.Header.Get("Link"); link != "" {
58 if resolvedRef, err := extractImmutableLink(link); err == nil {
59 newLink := fmt.Sprintf("<%s/%s/archive/%s.tar.gz>; rel=\"immutable\"",
60 rp.config.Core.BaseUrl(), f.DidSlashRepo(), resolvedRef)
61 w.Header().Set("Link", newLink)
62 }
63 }
64
65 // stream the archive data directly
66 if _, err := io.Copy(w, resp.Body); err != nil {
67 l.Error("failed to write response", "err", err)
68 }
69}
70
71func extractImmutableLink(linkHeader string) (string, error) {
72 trimmed := strings.TrimPrefix(linkHeader, "<")
73 trimmed = strings.TrimSuffix(trimmed, ">; rel=\"immutable\"")
74
75 parsedLink, err := url.Parse(trimmed)
76 if err != nil {
77 return "", err
78 }
79
80 resolvedRef := parsedLink.Query().Get("ref")
81 if resolvedRef == "" {
82 return "", fmt.Errorf("no ref found in link header")
83 }
84
85 return resolvedRef, nil
86}