// 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 }