grasp: better git error messages and get rid of stdout printing.
This commit is contained in:
@@ -5,6 +5,7 @@ import (
|
|||||||
"compress/gzip"
|
"compress/gzip"
|
||||||
"context"
|
"context"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
@@ -18,10 +19,9 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"fiatjaf.com/nostr"
|
"fiatjaf.com/nostr"
|
||||||
|
"fiatjaf.com/nostr/khatru"
|
||||||
"fiatjaf.com/nostr/nip19"
|
"fiatjaf.com/nostr/nip19"
|
||||||
"fiatjaf.com/nostr/nip34"
|
"fiatjaf.com/nostr/nip34"
|
||||||
|
|
||||||
"fiatjaf.com/nostr/khatru"
|
|
||||||
"github.com/go-git/go-git/v5/plumbing/format/pktline"
|
"github.com/go-git/go-git/v5/plumbing/format/pktline"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -147,7 +147,9 @@ func (gs *GraspServer) handleInfoRefs(
|
|||||||
switch serviceName {
|
switch serviceName {
|
||||||
case "git-upload-pack":
|
case "git-upload-pack":
|
||||||
if !gs.repoExists(pubkey, repoName) {
|
if !gs.repoExists(pubkey, repoName) {
|
||||||
gs.gitError(w, "repository not found", http.StatusNotFound)
|
w.Header().Set("content-type", "text/plain; charset=UTF-8")
|
||||||
|
w.WriteHeader(404)
|
||||||
|
fmt.Fprintf(w, "repository not found\n")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
w.Header().Set("Content-Type", "application/x-git-upload-pack-advertisement")
|
w.Header().Set("Content-Type", "application/x-git-upload-pack-advertisement")
|
||||||
@@ -157,7 +159,6 @@ func (gs *GraspServer) handleInfoRefs(
|
|||||||
|
|
||||||
repoPath := filepath.Join(gs.RepositoryDir, repoName)
|
repoPath := filepath.Join(gs.RepositoryDir, repoName)
|
||||||
if err := gs.runInfoRefs(w, r, repoPath); err != nil {
|
if err := gs.runInfoRefs(w, r, repoPath); err != nil {
|
||||||
fmt.Printf("runInfoRefs error: %s\n", err)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
case "git-receive-pack":
|
case "git-receive-pack":
|
||||||
@@ -172,7 +173,9 @@ func (gs *GraspServer) handleInfoRefs(
|
|||||||
v, _ := base64.StdEncoding.DecodeString("MDAxZiMgc2VydmljZT1naXQtcmVjZWl2ZS1wYWNrCjAwMDAwMGIxMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMCBjYXBhYmlsaXRpZXNee30AcmVwb3J0LXN0YXR1cyByZXBvcnQtc3RhdHVzLXYyIGRlbGV0ZS1yZWZzIHNpZGUtYmFuZC02NGsgcXVpZXQgYXRvbWljIG9mcy1kZWx0YSBvYmplY3QtZm9ybWF0PXNoYTEgYWdlbnQ9Z2l0LzIuNDMuMAowMDAw")
|
v, _ := base64.StdEncoding.DecodeString("MDAxZiMgc2VydmljZT1naXQtcmVjZWl2ZS1wYWNrCjAwMDAwMGIxMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMCBjYXBhYmlsaXRpZXNee30AcmVwb3J0LXN0YXR1cyByZXBvcnQtc3RhdHVzLXYyIGRlbGV0ZS1yZWZzIHNpZGUtYmFuZC02NGsgcXVpZXQgYXRvbWljIG9mcy1kZWx0YSBvYmplY3QtZm9ybWF0PXNoYTEgYWdlbnQ9Z2l0LzIuNDMuMAowMDAw")
|
||||||
w.Write(v)
|
w.Write(v)
|
||||||
default:
|
default:
|
||||||
gs.gitError(w, fmt.Sprintf("service unsupported: '%s'", serviceName), http.StatusForbidden)
|
w.Header().Set("content-type", "text/plain; charset=UTF-8")
|
||||||
|
w.WriteHeader(403)
|
||||||
|
fmt.Fprintf(w, "service unsupported: '%s'\n", serviceName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,14 +189,18 @@ func (gs *GraspServer) handleGitUploadPack(
|
|||||||
|
|
||||||
// for upload-pack (pull), check if repository exists
|
// for upload-pack (pull), check if repository exists
|
||||||
if !gs.repoExists(pubkey, repoName) {
|
if !gs.repoExists(pubkey, repoName) {
|
||||||
gs.gitError(w, "repository not found", http.StatusNotFound)
|
w.Header().Set("content-type", "text/plain; charset=UTF-8")
|
||||||
|
w.WriteHeader(404)
|
||||||
|
fmt.Fprintf(w, "repository not found\n")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if gs.OnRead != nil {
|
if gs.OnRead != nil {
|
||||||
reject, msg := gs.OnRead(r.Context(), pubkey, repoName)
|
reject, msg := gs.OnRead(r.Context(), pubkey, repoName)
|
||||||
if reject {
|
if reject {
|
||||||
gs.gitError(w, msg, http.StatusForbidden)
|
w.Header().Set("content-type", "text/plain; charset=UTF-8")
|
||||||
|
w.WriteHeader(403)
|
||||||
|
fmt.Fprintf(w, "%s\n", msg)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -201,7 +208,9 @@ func (gs *GraspServer) handleGitUploadPack(
|
|||||||
const expectedContentType = "application/x-git-upload-pack-request"
|
const expectedContentType = "application/x-git-upload-pack-request"
|
||||||
contentType := r.Header.Get("Content-Type")
|
contentType := r.Header.Get("Content-Type")
|
||||||
if contentType != expectedContentType {
|
if contentType != expectedContentType {
|
||||||
gs.gitError(w, fmt.Sprintf("expected Content-Type: '%s', but received '%s'", expectedContentType, contentType), http.StatusUnsupportedMediaType)
|
w.Header().Set("content-type", "text/plain; charset=UTF-8")
|
||||||
|
w.WriteHeader(415)
|
||||||
|
fmt.Fprintf(w, "expected Content-Type: '%s', but received '%s'\n", expectedContentType, contentType)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -209,8 +218,9 @@ func (gs *GraspServer) handleGitUploadPack(
|
|||||||
if r.Header.Get("Content-Encoding") == "gzip" {
|
if r.Header.Get("Content-Encoding") == "gzip" {
|
||||||
gzipReader, err := gzip.NewReader(r.Body)
|
gzipReader, err := gzip.NewReader(r.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
gs.gitError(w, err.Error(), http.StatusInternalServerError)
|
w.Header().Set("content-type", "text/plain; charset=UTF-8")
|
||||||
fmt.Printf("git: failed to create gzip reader, handler: UploadPack, error: %v\n", err)
|
w.WriteHeader(500)
|
||||||
|
fmt.Fprintf(w, "failed to create gzip reader, handler: UploadPack, error: %v\n", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer gzipReader.Close()
|
defer gzipReader.Close()
|
||||||
@@ -222,10 +232,10 @@ func (gs *GraspServer) handleGitUploadPack(
|
|||||||
w.Header().Set("Cache-Control", "no-cache, max-age=0, must-revalidate")
|
w.Header().Set("Cache-Control", "no-cache, max-age=0, must-revalidate")
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
|
|
||||||
fmt.Printf("git: executing git-upload-pack, handler: UploadPack, repo: %s\n", repoPath)
|
|
||||||
|
|
||||||
if err := gs.runUploadPack(w, r, repoPath, bodyReader); err != nil {
|
if err := gs.runUploadPack(w, r, repoPath, bodyReader); err != nil {
|
||||||
fmt.Printf("git: failed to execute git-upload-pack, handler: UploadPack, error: %v\n", err)
|
w.Header().Set("content-type", "text/plain; charset=UTF-8")
|
||||||
|
w.WriteHeader(http.StatusForbidden)
|
||||||
|
fmt.Fprintf(w, "failed to execute git-upload-pack, handler: UploadPack, error: %v\n", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -240,15 +250,19 @@ func (gs *GraspServer) handleGitReceivePack(
|
|||||||
body := &bytes.Buffer{}
|
body := &bytes.Buffer{}
|
||||||
io.Copy(body, r.Body)
|
io.Copy(body, r.Body)
|
||||||
|
|
||||||
if !gs.validatePush(r.Context(), pubkey, repoName, body.Bytes()) {
|
if err := gs.validatePush(r.Context(), pubkey, repoName, body.Bytes()); err != nil {
|
||||||
gs.gitError(w, "unauthorized push", http.StatusForbidden)
|
w.Header().Set("content-type", "text/plain; charset=UTF-8")
|
||||||
|
w.WriteHeader(403)
|
||||||
|
fmt.Fprintf(w, "unauthorized push: %v\n", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if gs.OnWrite != nil {
|
if gs.OnWrite != nil {
|
||||||
reject, msg := gs.OnWrite(r.Context(), pubkey, repoName)
|
reject, msg := gs.OnWrite(r.Context(), pubkey, repoName)
|
||||||
if reject {
|
if reject {
|
||||||
gs.gitError(w, msg, http.StatusForbidden)
|
w.Header().Set("content-type", "text/plain; charset=UTF-8")
|
||||||
|
w.WriteHeader(403)
|
||||||
|
fmt.Fprintf(w, "%s\n", msg)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -257,7 +271,9 @@ func (gs *GraspServer) handleGitReceivePack(
|
|||||||
|
|
||||||
// ensure repository directory exists
|
// ensure repository directory exists
|
||||||
if err := os.MkdirAll(repoPath, 0755); err != nil {
|
if err := os.MkdirAll(repoPath, 0755); err != nil {
|
||||||
gs.gitError(w, fmt.Sprintf("failed to create repository: %s", err), http.StatusInternalServerError)
|
w.Header().Set("content-type", "text/plain; charset=UTF-8")
|
||||||
|
w.WriteHeader(500)
|
||||||
|
fmt.Fprintf(w, "failed to create repository: %s\n", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -266,10 +282,11 @@ func (gs *GraspServer) handleGitReceivePack(
|
|||||||
cmd := exec.Command("git", "init", "--bare")
|
cmd := exec.Command("git", "init", "--bare")
|
||||||
cmd.Dir = repoPath
|
cmd.Dir = repoPath
|
||||||
if output, err := cmd.CombinedOutput(); err != nil {
|
if output, err := cmd.CombinedOutput(); err != nil {
|
||||||
gs.gitError(w, fmt.Sprintf("failed to initialize repository: %s, output: %s", err, string(output)), http.StatusInternalServerError)
|
w.Header().Set("content-type", "text/plain; charset=UTF-8")
|
||||||
|
w.WriteHeader(500)
|
||||||
|
fmt.Fprintf(w, "failed to initialize repository: %s, output: %s\n", err, string(output))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fmt.Printf("initialized new git repository at %s\n", repoPath)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/x-git-receive-pack-result")
|
w.Header().Set("Content-Type", "application/x-git-receive-pack-result")
|
||||||
@@ -278,14 +295,18 @@ func (gs *GraspServer) handleGitReceivePack(
|
|||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
|
|
||||||
if err := gs.runReceivePack(w, r, repoPath, io.NopCloser(bytes.NewReader(body.Bytes()))); err != nil {
|
if err := gs.runReceivePack(w, r, repoPath, io.NopCloser(bytes.NewReader(body.Bytes()))); err != nil {
|
||||||
fmt.Printf("runReceivePack error: %s\n", err)
|
w.Header().Set("content-type", "text/plain; charset=UTF-8")
|
||||||
|
w.WriteHeader(http.StatusForbidden)
|
||||||
|
fmt.Fprintf(w, "runReceivePack: %v\n", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// update HEAD per state announcement
|
// update HEAD per state announcement
|
||||||
if err := gs.updateHEAD(r.Context(), pubkey, repoName, repoPath); err != nil {
|
if err := gs.updateHEAD(r.Context(), pubkey, repoName, repoPath); err != nil {
|
||||||
fmt.Printf("failed to update HEAD: %s\n", err)
|
w.Header().Set("content-type", "text/plain; charset=UTF-8")
|
||||||
// don't fail the push, just log
|
w.WriteHeader(http.StatusForbidden)
|
||||||
|
fmt.Fprintf(w, "failed to update HEAD: %v\n", err)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// cleanup merged patches
|
// cleanup merged patches
|
||||||
@@ -298,11 +319,10 @@ func (gs *GraspServer) validatePush(
|
|||||||
pubkey nostr.PubKey,
|
pubkey nostr.PubKey,
|
||||||
repoName string,
|
repoName string,
|
||||||
bodyBytes []byte,
|
bodyBytes []byte,
|
||||||
) bool {
|
) error {
|
||||||
// query for repository state events (kind 30618)
|
// query for repository state events (kind 30618)
|
||||||
if gs.Relay.QueryStored == nil {
|
if gs.Relay.QueryStored == nil {
|
||||||
fmt.Printf("relay has no QueryStored function\n")
|
return errors.New("relay has no QueryStored function")
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// check state
|
// check state
|
||||||
@@ -316,7 +336,7 @@ func (gs *GraspServer) validatePush(
|
|||||||
state = nip34.ParseRepositoryState(evt)
|
state = nip34.ParseRepositoryState(evt)
|
||||||
}
|
}
|
||||||
if state.Event.ID == nostr.ZeroID {
|
if state.Event.ID == nostr.ZeroID {
|
||||||
return false
|
return fmt.Errorf("no state found for repository '%s'", repoName)
|
||||||
}
|
}
|
||||||
|
|
||||||
// get repository announcement to check maintainers
|
// get repository announcement to check maintainers
|
||||||
@@ -330,20 +350,19 @@ func (gs *GraspServer) validatePush(
|
|||||||
announcement = nip34.ParseRepository(evt)
|
announcement = nip34.ParseRepository(evt)
|
||||||
}
|
}
|
||||||
if announcement.Event.ID == nostr.ZeroID {
|
if announcement.Event.ID == nostr.ZeroID {
|
||||||
return false
|
return fmt.Errorf("no announcement found for repository '%s'", repoName)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ensure pusher is authorized (owner or maintainer)
|
// ensure pusher is authorized (owner or maintainer)
|
||||||
if pubkey != announcement.PubKey && !slices.Contains(announcement.Maintainers, pubkey) {
|
if pubkey != announcement.PubKey && !slices.Contains(announcement.Maintainers, pubkey) {
|
||||||
return false
|
return fmt.Errorf("pusher '%s' is not authorized for repository '%s'", pubkey, repoName)
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse pktline to extract and validate all push refs
|
// parse pktline to extract and validate all push refs
|
||||||
pkt := pktline.NewScanner(bytes.NewReader(bodyBytes))
|
pkt := pktline.NewScanner(bytes.NewReader(bodyBytes))
|
||||||
for pkt.Scan() {
|
for pkt.Scan() {
|
||||||
if err := pkt.Err(); err != nil {
|
if err := pkt.Err(); err != nil {
|
||||||
fmt.Printf("invalid pkt: %v\n", err)
|
return fmt.Errorf("invalid pkt: %v", err)
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
line := string(pkt.Bytes())
|
line := string(pkt.Bytes())
|
||||||
if len(line) < 40 {
|
if len(line) < 40 {
|
||||||
@@ -361,8 +380,7 @@ func (gs *GraspServer) validatePush(
|
|||||||
eventId := ref[11:]
|
eventId := ref[11:]
|
||||||
id, err := nostr.IDFromHex(eventId)
|
id, err := nostr.IDFromHex(eventId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("push rejected: invalid event id %s\n", eventId)
|
return fmt.Errorf("push rejected: invalid event id %s", eventId)
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
var foundEvent bool
|
var foundEvent bool
|
||||||
for evt := range gs.Relay.QueryStored(ctx, nostr.Filter{
|
for evt := range gs.Relay.QueryStored(ctx, nostr.Filter{
|
||||||
@@ -377,15 +395,13 @@ func (gs *GraspServer) validatePush(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !hasMatchingCommit {
|
if !hasMatchingCommit {
|
||||||
fmt.Printf("push rejected: event %s has different tip (expected %s)\n", eventId, to)
|
return fmt.Errorf("push rejected: event %s has different tip (expected %s)", eventId, to)
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
foundEvent = true
|
foundEvent = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if !foundEvent {
|
if !foundEvent {
|
||||||
fmt.Printf("push rejected: event %s not found\n", eventId)
|
return fmt.Errorf("push rejected: event %s not found", eventId)
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -395,16 +411,13 @@ func (gs *GraspServer) validatePush(
|
|||||||
branchName := ref[11:]
|
branchName := ref[11:]
|
||||||
// pushing a branch
|
// pushing a branch
|
||||||
if commitId, exists := state.Branches[branchName]; exists && to == commitId {
|
if commitId, exists := state.Branches[branchName]; exists && to == commitId {
|
||||||
fmt.Printf("push accepted: %s %s->%s\n", ref, from, to)
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// deleting a branch
|
// deleting a branch
|
||||||
if _, exists := state.Branches[branchName]; to == zeroRef && !exists {
|
if _, exists := state.Branches[branchName]; to == zeroRef && !exists {
|
||||||
fmt.Printf("delete accepted: %s\n", ref)
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
fmt.Printf("push unauthorized: ref %s %s->%s does not match state\n", ref, from, to)
|
return fmt.Errorf("push unauthorized: ref %s %s->%s does not match state", ref, from, to)
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// validate tag pushes
|
// validate tag pushes
|
||||||
@@ -412,20 +425,17 @@ func (gs *GraspServer) validatePush(
|
|||||||
tagName := ref[10:]
|
tagName := ref[10:]
|
||||||
// pushing a tag
|
// pushing a tag
|
||||||
if commitId, exists := state.Tags[tagName]; exists && to == commitId {
|
if commitId, exists := state.Tags[tagName]; exists && to == commitId {
|
||||||
fmt.Printf("push accepted: %s %s->%s\n", ref, from, to)
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// deleting a tag
|
// deleting a tag
|
||||||
if _, exists := state.Tags[tagName]; to == zeroRef && !exists {
|
if _, exists := state.Tags[tagName]; to == zeroRef && !exists {
|
||||||
fmt.Printf("delete accepted: %s\n", ref)
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
fmt.Printf("push unauthorized: ref %s %s->%s does not match state\n", ref, from, to)
|
return fmt.Errorf("push unauthorized: ref %s %s->%s does not match state", ref, from, to)
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// repoExists checks if a repository has an announcement event (kind 30617)
|
// repoExists checks if a repository has an announcement event (kind 30617)
|
||||||
@@ -603,8 +613,6 @@ func (gs *GraspServer) updateHEAD(ctx context.Context, pubkey nostr.PubKey, repo
|
|||||||
if output, err := cmd.CombinedOutput(); err != nil {
|
if output, err := cmd.CombinedOutput(); err != nil {
|
||||||
return fmt.Errorf("failed to update HEAD: %w, output: %s", err, string(output))
|
return fmt.Errorf("failed to update HEAD: %w, output: %s", err, string(output))
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("updated HEAD to %s for repo %s\n", latestState.HEAD, repoName)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -678,9 +686,9 @@ func (gs *GraspServer) cleanupMergedPatches(ctx context.Context, pubkey nostr.Pu
|
|||||||
cmd := exec.Command("git", "update-ref", "-d", ref)
|
cmd := exec.Command("git", "update-ref", "-d", ref)
|
||||||
cmd.Dir = repoPath
|
cmd.Dir = repoPath
|
||||||
if err := cmd.Run(); err != nil {
|
if err := cmd.Run(); err != nil {
|
||||||
fmt.Printf("failed to delete ref %s: %s\n", ref, err)
|
fmt.Fprintf(os.Stderr, "failed to delete ref %s: %s\n", ref, err)
|
||||||
} else {
|
} else {
|
||||||
fmt.Printf("deleted ref %s (no corresponding event)\n", ref)
|
fmt.Fprintf(os.Stderr, "deleted ref %s (no corresponding event)\n", ref)
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -703,9 +711,9 @@ func (gs *GraspServer) cleanupMergedPatches(ctx context.Context, pubkey nostr.Pu
|
|||||||
cmd := exec.Command("git", "update-ref", "-d", ref)
|
cmd := exec.Command("git", "update-ref", "-d", ref)
|
||||||
cmd.Dir = repoPath
|
cmd.Dir = repoPath
|
||||||
if err := cmd.Run(); err != nil {
|
if err := cmd.Run(); err != nil {
|
||||||
fmt.Printf("failed to delete ref %s: %s\n", ref, err)
|
fmt.Fprintf(os.Stderr, "failed to delete ref %s: %s\n", ref, err)
|
||||||
} else {
|
} else {
|
||||||
fmt.Printf("deleted ref %s (merged into %s)\n", ref, branchName)
|
fmt.Fprintf(os.Stderr, "deleted ref %s (merged into %s)\n", ref, branchName)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -743,13 +751,6 @@ func (gs *GraspServer) serveRepoPage(w http.ResponseWriter, r *http.Request, npu
|
|||||||
fmt.Fprint(w, html)
|
fmt.Fprint(w, html)
|
||||||
}
|
}
|
||||||
|
|
||||||
// gitError writes a git error response
|
|
||||||
func (gs *GraspServer) gitError(w http.ResponseWriter, msg string, status int) {
|
|
||||||
w.Header().Set("content-type", "text/plain; charset=UTF-8")
|
|
||||||
w.WriteHeader(status)
|
|
||||||
fmt.Fprintf(w, "%s\n", msg)
|
|
||||||
}
|
|
||||||
|
|
||||||
// packLine writes a pktline formatted line
|
// packLine writes a pktline formatted line
|
||||||
func (gs *GraspServer) packLine(w io.Writer, s string) error {
|
func (gs *GraspServer) packLine(w io.Writer, s string) error {
|
||||||
_, err := fmt.Fprintf(w, "%04x%s", len(s)+4, s)
|
_, err := fmt.Fprintf(w, "%04x%s", len(s)+4, s)
|
||||||
|
|||||||
Reference in New Issue
Block a user