diff options
Diffstat (limited to 'http_handle_repo_raw.go')
-rw-r--r-- | http_handle_repo_raw.go | 159 |
1 files changed, 96 insertions, 63 deletions
diff --git a/http_handle_repo_raw.go b/http_handle_repo_raw.go index 75296d6..5928f8c 100644 --- a/http_handle_repo_raw.go +++ b/http_handle_repo_raw.go @@ -4,102 +4,135 @@ package main import ( + "errors" "fmt" + "html/template" + "io" + "net" "net/http" "strings" - "time" - "github.com/go-git/go-git/v5" - "github.com/go-git/go-git/v5/plumbing" - "github.com/go-git/go-git/v5/plumbing/object" + "git.sr.ht/~sircmpwn/go-bare" ) // httpHandleRepoRaw serves raw files, or directory listings that point to raw // files. func httpHandleRepoRaw(writer http.ResponseWriter, request *http.Request, params map[string]any) { - var rawPathSpec, pathSpec string - var repo *git.Repository - var refHash plumbing.Hash - var refHashSlice []byte - var commitObj *object.Commit - var tree *object.Tree - var err error - - rawPathSpec = params["rest"].(string) - repo, pathSpec = params["repo"].(*git.Repository), strings.TrimSuffix(rawPathSpec, "/") + repoName := params["repo_name"].(string) + groupPath := params["group_path"].([]string) + rawPathSpec := params["rest"].(string) + pathSpec := strings.TrimSuffix(rawPathSpec, "/") params["path_spec"] = pathSpec - if refHash, err = getRefHash(repo, params["ref_type"].(string), params["ref_name"].(string)); err != nil { - errorPage500(writer, params, "Error getting ref hash: "+err.Error()) + _, repoPath, _, _, _, _, _ := getRepoInfo(request.Context(), groupPath, repoName, "") + + conn, err := net.Dial("unix", config.Git.Socket) + if err != nil { + errorPage500(writer, params, "git2d connection failed: "+err.Error()) return } - refHashSlice = refHash[:] + defer conn.Close() - cacheHandle := append(refHashSlice, stringToBytes(pathSpec)...) //nolint:gocritic + brWriter := bare.NewWriter(conn) + brReader := bare.NewReader(conn) - if value, found := treeReadmeCache.Get(cacheHandle); found { - params["files"] = value.DisplayTree - renderTemplate(writer, "repo_raw_dir", params) + if err := brWriter.WriteData([]byte(repoPath)); err != nil { + errorPage500(writer, params, "sending repo path failed: "+err.Error()) return } - if value, found := commitPathFileRawCache.Get(cacheHandle); found { - fmt.Fprint(writer, value) + if err := brWriter.WriteUint(2); err != nil { + errorPage500(writer, params, "sending command failed: "+err.Error()) return } - - if commitObj, err = repo.CommitObject(refHash); err != nil { - errorPage500(writer, params, "Error getting commit object: "+err.Error()) + if err := brWriter.WriteData([]byte(pathSpec)); err != nil { + errorPage500(writer, params, "sending path failed: "+err.Error()) return } - if tree, err = commitObj.Tree(); err != nil { - errorPage500(writer, params, "Error getting file tree: "+err.Error()) + + status, err := brReader.ReadUint() + if err != nil { + errorPage500(writer, params, "reading status failed: "+err.Error()) return } - start := time.Now() - var target *object.Tree - if pathSpec == "" { - target = tree - } else { - if target, err = tree.Tree(pathSpec); err != nil { - var file *object.File - var fileContent string - if file, err = tree.File(pathSpec); err != nil { - errorPage500(writer, params, "Error retrieving path: "+err.Error()) + switch status { + case 0: + kind, err := brReader.ReadUint() + if err != nil { + errorPage500(writer, params, "reading object kind failed: "+err.Error()) + return + } + + switch kind { + case 1: + // Tree + if redirectDir(writer, request) { return } + count, err := brReader.ReadUint() + if err != nil { + errorPage500(writer, params, "reading entry count failed: "+err.Error()) + return + } + + files := make([]displayTreeEntry, 0, count) + for i := uint64(0); i < count; i++ { + typeCode, err := brReader.ReadUint() + if err != nil { + errorPage500(writer, params, "error reading entry type: "+err.Error()) + return + } + mode, err := brReader.ReadUint() + if err != nil { + errorPage500(writer, params, "error reading entry mode: "+err.Error()) + return + } + size, err := brReader.ReadUint() + if err != nil { + errorPage500(writer, params, "error reading entry size: "+err.Error()) + return + } + name, err := brReader.ReadData() + if err != nil { + errorPage500(writer, params, "error reading entry name: "+err.Error()) + return + } + files = append(files, displayTreeEntry{ + Name: string(name), + Mode: fmt.Sprintf("%06o", mode), + Size: int64(size), + IsFile: typeCode == 2, + IsSubtree: typeCode == 1, + }) + } + + params["files"] = files + params["readme_filename"] = "README.md" + params["readme"] = template.HTML("<p>README rendering here is WIP again</p>") // TODO + + renderTemplate(writer, "repo_raw_dir", params) + + case 2: + // Blob if redirectNoDir(writer, request) { return } - if fileContent, err = file.Contents(); err != nil { - errorPage500(writer, params, "Error reading file: "+err.Error()) + content, err := brReader.ReadData() + if err != nil && !errors.Is(err, io.EOF) { + errorPage500(writer, params, "error reading blob content: "+err.Error()) return } - cost := time.Since(start).Nanoseconds() - commitPathFileRawCache.Set(cacheHandle, fileContent, cost) writer.Header().Set("Content-Type", "application/octet-stream") - fmt.Fprint(writer, fileContent) - return - } - } + fmt.Fprint(writer, string(content)) - if redirectDir(writer, request) { - return - } - - displayTree := makeDisplayTree(target) - readmeFilename, readmeRendered := renderReadmeAtTree(target) - cost := time.Since(start).Nanoseconds() - - params["files"] = displayTree - params["readme_filename"] = readmeFilename - params["readme"] = readmeRendered + default: + errorPage500(writer, params, fmt.Sprintf("unknown object kind: %d", kind)) + } - treeReadmeCache.Set(cacheHandle, treeReadmeCacheEntry{ - DisplayTree: displayTree, - ReadmeFilename: readmeFilename, - ReadmeRendered: readmeRendered, - }, cost) + case 3: + errorPage500(writer, params, fmt.Sprintf("path not found: %s", pathSpec)) - renderTemplate(writer, "repo_raw_dir", params) + default: + errorPage500(writer, params, fmt.Sprintf("unknown status code: %d", status)) + } } |