all repos

mugit @ 2d21be8e8bdb9a2d9d01e55310508ee3dd398ae6

🐮 git server that your cow will love
4 files changed, 35 insertions(+), 18 deletions(-)
serve raw files on separate route
Author: Oleksandr Smirnov olexsmir@gmail.com
Committed at: 2026-03-09 18:21:37 +0200
Authored at: 2026-03-09 18:20:03 +0200
Change ID: zoxtzxxqlvrnzxzrzoxmwmyxnvtrosqr
Parent: bdfa44c
M internal/handlers/handlers.go
···
        46
        46
         	mux.HandleFunc("GET /{name}/feed/{$}", h.repoFeedHandler)

      
        47
        47
         	mux.HandleFunc("GET /{name}/tree/{ref}/{rest...}", h.repoTreeHandler)

      
        48
        48
         	mux.HandleFunc("GET /{name}/blob/{ref}/{rest...}", h.fileContentsHandler)

      
        
        49
        +	mux.HandleFunc("GET /{name}/raw/{ref}/{rest...}", h.rawFileContentsHandler)

      
        49
        50
         	mux.HandleFunc("GET /{name}/log/{ref}", h.logHandler)

      
        50
        51
         	mux.HandleFunc("GET /{name}/commit/{ref}", h.commitHandler)

      
        51
        52
         	mux.HandleFunc("GET /{name}/refs/{$}", h.refsHandler)

      
M internal/handlers/repo.go
···
        11
        11
         	"os"

      
        12
        12
         	"path/filepath"

      
        13
        13
         	"sort"

      
        14
        
        -	"strconv"

      
        15
        14
         	"strings"

      
        16
        15
         	"time"

      
        17
        16
         

      ···
        177
        176
         	ref := h.parseRef(r.PathValue("ref"))

      
        178
        177
         	treePath := r.PathValue("rest")

      
        179
        178
         

      
        180
        
        -	var raw bool

      
        181
        
        -	if rawParam, err := strconv.ParseBool(r.URL.Query().Get("raw")); err == nil {

      
        182
        
        -		raw = rawParam

      
        183
        
        -	}

      
        184
        
        -

      
        185
        179
         	repo, err := h.openPublicRepo(name, ref)

      
        186
        180
         	if err != nil {

      
        187
        181
         		h.write404(w, err)

      ···
        195
        189
         			return

      
        196
        190
         		}

      
        197
        191
         		h.write500(w, err)

      
        198
        
        -		return

      
        199
        
        -	}

      
        200
        
        -

      
        201
        
        -	if raw {

      
        202
        
        -		w.Header().Set("Content-Type", fc.Mime)

      
        203
        
        -		w.WriteHeader(http.StatusOK)

      
        204
        
        -		w.Write(fc.Content)

      
        205
        192
         		return

      
        206
        193
         	}

      
        207
        194
         

      ···
        236
        223
         	}

      
        237
        224
         

      
        238
        225
         	h.templ(w, "repo_file", h.pageData(repo, p))

      
        
        226
        +}

      
        
        227
        +

      
        
        228
        +func (h *handlers) rawFileContentsHandler(w http.ResponseWriter, r *http.Request) {

      
        
        229
        +	name := r.PathValue("name")

      
        
        230
        +	ref := h.parseRef(r.PathValue("ref"))

      
        
        231
        +	treePath := r.PathValue("rest")

      
        
        232
        +

      
        
        233
        +	repo, err := h.openPublicRepo(name, ref)

      
        
        234
        +	if err != nil {

      
        
        235
        +		w.WriteHeader(http.StatusNotFound)

      
        
        236
        +		slog.Info("404", "err", err)

      
        
        237
        +		return

      
        
        238
        +	}

      
        
        239
        +

      
        
        240
        +	fc, err := repo.FileContent(treePath)

      
        
        241
        +	if err != nil {

      
        
        242
        +		if errors.Is(err, git.ErrFileNotFound) {

      
        
        243
        +			w.WriteHeader(http.StatusNotFound)

      
        
        244
        +			slog.Info("404", "err", err)

      
        
        245
        +			return

      
        
        246
        +		}

      
        
        247
        +

      
        
        248
        +		w.WriteHeader(http.StatusInternalServerError)

      
        
        249
        +		slog.Info("500", "err", err)

      
        
        250
        +		return

      
        
        251
        +	}

      
        
        252
        +

      
        
        253
        +	w.Header().Set("Content-Type", fc.Mime)

      
        
        254
        +	w.WriteHeader(http.StatusOK)

      
        
        255
        +	w.Write(fc.Content)

      
        239
        256
         }

      
        240
        257
         

      
        241
        258
         type RepoLog struct {

      
M internal/markdown/relink.go
···
        87
        87
         	}

      
        88
        88
         

      
        89
        89
         	absPath := m.path(dst)

      
        90
        
        -	return path.Join("/", url.PathEscape(m.repoName), "blob", m.repoRef, absPath) +

      
        91
        
        -		"?raw=true"

      
        
        90
        +	return path.Join("/", url.PathEscape(m.repoName), "raw", m.repoRef, absPath)

      
        92
        91
         }

      
        93
        92
         

      
        94
        93
         func (m *relLinkTransformer) path(dst string) string {

      
M web/templates/repo_file.html
···
        14
        14
                 {{- if .IsLast -}}{{- .Name -}}

      
        15
        15
                 {{- else -}}<a class="link" href="/{{ $.RepoName }}/tree/{{ $.P.Ref }}/{{ .Path }}">{{ .Name }}</a>{{- end -}}

      
        16
        16
                 {{- end -}}

      
        17
        
        -        (<a class="muted" href="?raw=true">view raw</a>)

      
        
        17
        +        (<a class="muted" href="/{{ .RepoName }}/raw/{{ .P.Ref }}/{{ .P.Path }}">view raw</a>)

      
        18
        18
               </p>

      
        19
        19
               <div class="file-wrapper">

      
        20
        20
                 {{ if .P.IsImage }}

      
        21
        21
                 <div class="image-viewer">

      
        22
        22
                   <p>{{ .P.Mime }} • {{ .P.Size }} bytes</p>

      
        23
        
        -          <img src="?raw=true" alt="{{- .P.Path -}}">

      
        
        23
        +          <img src="/{{ .RepoName }}/raw/{{ .P.Ref }}/{{ .P.Path }}" alt="{{- .P.Path -}}">

      
        24
        24
                 </div>

      
        25
        25
                 {{ else if .P.IsBinary }}

      
        26
        26
                 <div class="binary-viewer">

      
        27
        27
                   <p>Binary file ({{ .P.Mime }})</p>

      
        28
        28
                   <p>Size: {{ .P.Size }} bytes</p>

      
        29
        
        -          <a class="link" href="?raw=true" download>[ Download ]</a>

      
        
        29
        +          <a class="link" href="/{{ .RepoName }}/raw/{{ .P.Ref }}/{{ .P.Path }}" download>[ Download ]</a>

      
        30
        30
                 </div>

      
        31
        31
                 {{ else }}

      
        32
        32
                 <table>