eclipse/cmd/gitcached/githttp.go

68 lines
1.8 KiB
Go

// Copyright (C) 2024 Umorpha Systems
// SPDX-License-Identifier: AGPL-3.0-or-later
package main
import (
"fmt"
"net/http"
"net/url"
"regexp"
"strings"
)
// - /HEAD
// - /objects/[0-9a-f]{2}/[0-9a-f]{38}
// - /objects/pack/
// - /objects/info/packs (*)
// - /objects/info/alternates
// - /objects/info/http-alternates
// - /info/refs (*)
var reGitHTTP = regexp.MustCompile(`^.*/(?:` +
`HEAD` + `|` +
`objects(?:/[/a-z0-9]*)?` + `|` +
`info/refs(?:[?&](?:service=[-_a-z0-9]+)$` + `)` +
`)$`)
// routeGitHTTP takes a gitprotocol-http(5) request and parses it into
// a repoPath component and a service query component.
//
// - Returns ("", "", "", nil) if the request does not look like a
// gitprotocol-http(5) request.
//
// Returns ("", "", err) if the request looks like a
// gitprotocol-http(5) request, but has a malformed query string.
func routeGitHTTP(r *http.Request) (repoPath, file, service string, err error) {
idx := strings.LastIndex(r.RequestURI, "/info/refs")
if idx < 0 {
return "", "", "", nil
}
repoPath = r.RequestURI[:idx]
rawQuery := r.RequestURI[idx+len("/info/refs"):]
var query url.Values
if rawQuery != "" {
queryPrefix := "?"
if strings.Contains(repoPath, "?") {
queryPrefix = "&"
}
if !strings.HasPrefix(rawQuery, queryPrefix) {
return "", "", "", nil
}
var err error
query, err = url.ParseQuery(rawQuery[len(queryPrefix):])
if err != nil {
return "", "", "", fmt.Errorf("invalid query string: %w", err)
}
if len(query) > 1 || len(query["service"]) > 1 {
return "", "", "", fmt.Errorf("invalid query string: too many query parameters")
}
if len(query) > 0 && query["service"] == nil {
return "", "", "", fmt.Errorf("invalid query string: unexpected query parameters")
}
}
return repoPath, "TODO", query.Get("service"), nil
}