summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--build/generate-emoji.go4
-rw-r--r--cmd/hook.go144
-rw-r--r--cmd/hook_test.go10
-rw-r--r--cmd/keys.go9
-rw-r--r--cmd/mailer.go12
-rw-r--r--cmd/manager.go49
-rw-r--r--cmd/manager_logging.go93
-rw-r--r--cmd/restore_repo.go12
-rw-r--r--cmd/serv.go97
-rw-r--r--modules/httplib/httplib.go14
-rw-r--r--modules/private/hook.go125
-rw-r--r--modules/private/internal.go56
-rw-r--r--modules/private/key.go35
-rw-r--r--modules/private/mail.go34
-rw-r--r--modules/private/manager.go171
-rw-r--r--modules/private/request.go135
-rw-r--r--modules/private/restore_repo.go34
-rw-r--r--modules/private/serv.go65
-rw-r--r--routers/private/default_branch.go14
-rw-r--r--routers/private/hook_post_receive.go1
-rw-r--r--routers/private/hook_pre_receive.go39
-rw-r--r--routers/private/hook_proc_receive.go5
-rw-r--r--routers/private/hook_verification.go14
-rw-r--r--routers/private/internal.go2
-rw-r--r--routers/private/internal_repo.go26
-rw-r--r--routers/private/key.go1
-rw-r--r--routers/private/manager.go4
-rw-r--r--routers/private/manager_windows.go2
-rw-r--r--routers/private/serv.go141
-rw-r--r--tests/integration/api_private_serv_test.go48
30 files changed, 546 insertions, 850 deletions
diff --git a/build/generate-emoji.go b/build/generate-emoji.go
index 60350336c1..09bdeb6808 100644
--- a/build/generate-emoji.go
+++ b/build/generate-emoji.go
@@ -60,13 +60,13 @@ func main() {
// generate data
buf, err := generate()
if err != nil {
- log.Fatal(err)
+ log.Fatalf("generate err: %v", err)
}
// write
err = os.WriteFile(*flagOut, buf, 0o644)
if err != nil {
- log.Fatal(err)
+ log.Fatalf("WriteFile err: %v", err)
}
}
diff --git a/cmd/hook.go b/cmd/hook.go
index a62ffdde5f..9605fcb331 100644
--- a/cmd/hook.go
+++ b/cmd/hook.go
@@ -6,9 +6,9 @@ package cmd
import (
"bufio"
"bytes"
+ "context"
"fmt"
"io"
- "net/http"
"os"
"strconv"
"strings"
@@ -167,11 +167,11 @@ func runHookPreReceive(c *cli.Context) error {
ctx, cancel := installSignals()
defer cancel()
- setup("hooks/pre-receive.log", c.Bool("debug"))
+ setup(ctx, c.Bool("debug"))
if len(os.Getenv("SSH_ORIGINAL_COMMAND")) == 0 {
if setting.OnlyAllowPushIfGiteaEnvironmentSet {
- return fail(`Rejecting changes as Gitea environment not set.
+ return fail(ctx, `Rejecting changes as Gitea environment not set.
If you are pushing over SSH you must push with a key managed by
Gitea or set your environment appropriately.`, "")
}
@@ -257,14 +257,9 @@ Gitea or set your environment appropriately.`, "")
hookOptions.OldCommitIDs = oldCommitIDs
hookOptions.NewCommitIDs = newCommitIDs
hookOptions.RefFullNames = refFullNames
- statusCode, msg := private.HookPreReceive(ctx, username, reponame, hookOptions)
- switch statusCode {
- case http.StatusOK:
- // no-op
- case http.StatusInternalServerError:
- return fail("Internal Server Error", msg)
- default:
- return fail(msg, "")
+ extra := private.HookPreReceive(ctx, username, reponame, hookOptions)
+ if extra.HasError() {
+ return fail(ctx, extra.UserMsg, "HookPreReceive(batch) failed: %v", extra.Error)
}
count = 0
lastline = 0
@@ -285,12 +280,9 @@ Gitea or set your environment appropriately.`, "")
fmt.Fprintf(out, " Checking %d references\n", count)
- statusCode, msg := private.HookPreReceive(ctx, username, reponame, hookOptions)
- switch statusCode {
- case http.StatusInternalServerError:
- return fail("Internal Server Error", msg)
- case http.StatusForbidden:
- return fail(msg, "")
+ extra := private.HookPreReceive(ctx, username, reponame, hookOptions)
+ if extra.HasError() {
+ return fail(ctx, extra.UserMsg, "HookPreReceive(last) failed: %v", extra.Error)
}
} else if lastline > 0 {
fmt.Fprintf(out, "\n")
@@ -309,7 +301,7 @@ func runHookPostReceive(c *cli.Context) error {
ctx, cancel := installSignals()
defer cancel()
- setup("hooks/post-receive.log", c.Bool("debug"))
+ setup(ctx, c.Bool("debug"))
// First of all run update-server-info no matter what
if _, _, err := git.NewCommand(ctx, "update-server-info").RunStdString(nil); err != nil {
@@ -323,7 +315,7 @@ func runHookPostReceive(c *cli.Context) error {
if len(os.Getenv("SSH_ORIGINAL_COMMAND")) == 0 {
if setting.OnlyAllowPushIfGiteaEnvironmentSet {
- return fail(`Rejecting changes as Gitea environment not set.
+ return fail(ctx, `Rejecting changes as Gitea environment not set.
If you are pushing over SSH you must push with a key managed by
Gitea or set your environment appropriately.`, "")
}
@@ -394,11 +386,11 @@ Gitea or set your environment appropriately.`, "")
hookOptions.OldCommitIDs = oldCommitIDs
hookOptions.NewCommitIDs = newCommitIDs
hookOptions.RefFullNames = refFullNames
- resp, err := private.HookPostReceive(ctx, repoUser, repoName, hookOptions)
- if resp == nil {
+ resp, extra := private.HookPostReceive(ctx, repoUser, repoName, hookOptions)
+ if extra.HasError() {
_ = dWriter.Close()
hookPrintResults(results)
- return fail("Internal Server Error", err)
+ return fail(ctx, extra.UserMsg, "HookPostReceive failed: %v", extra.Error)
}
wasEmpty = wasEmpty || resp.RepoWasEmpty
results = append(results, resp.Results...)
@@ -409,9 +401,9 @@ Gitea or set your environment appropriately.`, "")
if count == 0 {
if wasEmpty && masterPushed {
// We need to tell the repo to reset the default branch to master
- err := private.SetDefaultBranch(ctx, repoUser, repoName, "master")
- if err != nil {
- return fail("Internal Server Error", "SetDefaultBranch failed with Error: %v", err)
+ extra := private.SetDefaultBranch(ctx, repoUser, repoName, "master")
+ if extra.HasError() {
+ return fail(ctx, extra.UserMsg, "SetDefaultBranch failed: %v", extra.Error)
}
}
fmt.Fprintf(out, "Processed %d references in total\n", total)
@@ -427,11 +419,11 @@ Gitea or set your environment appropriately.`, "")
fmt.Fprintf(out, " Processing %d references\n", count)
- resp, err := private.HookPostReceive(ctx, repoUser, repoName, hookOptions)
+ resp, extra := private.HookPostReceive(ctx, repoUser, repoName, hookOptions)
if resp == nil {
_ = dWriter.Close()
hookPrintResults(results)
- return fail("Internal Server Error", err)
+ return fail(ctx, extra.UserMsg, "HookPostReceive failed: %v", extra.Error)
}
wasEmpty = wasEmpty || resp.RepoWasEmpty
results = append(results, resp.Results...)
@@ -440,9 +432,9 @@ Gitea or set your environment appropriately.`, "")
if wasEmpty && masterPushed {
// We need to tell the repo to reset the default branch to master
- err := private.SetDefaultBranch(ctx, repoUser, repoName, "master")
- if err != nil {
- return fail("Internal Server Error", "SetDefaultBranch failed with Error: %v", err)
+ extra := private.SetDefaultBranch(ctx, repoUser, repoName, "master")
+ if extra.HasError() {
+ return fail(ctx, extra.UserMsg, "SetDefaultBranch failed: %v", extra.Error)
}
}
_ = dWriter.Close()
@@ -485,22 +477,22 @@ func pushOptions() map[string]string {
}
func runHookProcReceive(c *cli.Context) error {
- setup("hooks/proc-receive.log", c.Bool("debug"))
+ ctx, cancel := installSignals()
+ defer cancel()
+
+ setup(ctx, c.Bool("debug"))
if len(os.Getenv("SSH_ORIGINAL_COMMAND")) == 0 {
if setting.OnlyAllowPushIfGiteaEnvironmentSet {
- return fail(`Rejecting changes as Gitea environment not set.
+ return fail(ctx, `Rejecting changes as Gitea environment not set.
If you are pushing over SSH you must push with a key managed by
Gitea or set your environment appropriately.`, "")
}
return nil
}
- ctx, cancel := installSignals()
- defer cancel()
-
if git.CheckGitVersionAtLeast("2.29") != nil {
- return fail("Internal Server Error", "git not support proc-receive.")
+ return fail(ctx, "No proc-receive support", "current git version doesn't support proc-receive.")
}
reader := bufio.NewReader(os.Stdin)
@@ -515,7 +507,7 @@ Gitea or set your environment appropriately.`, "")
// H: PKT-LINE(version=1\0push-options...)
// H: flush-pkt
- rs, err := readPktLine(reader, pktLineTypeData)
+ rs, err := readPktLine(ctx, reader, pktLineTypeData)
if err != nil {
return err
}
@@ -530,19 +522,19 @@ Gitea or set your environment appropriately.`, "")
index := bytes.IndexByte(rs.Data, byte(0))
if index >= len(rs.Data) {
- return fail("Internal Server Error", "pkt-line: format error "+fmt.Sprint(rs.Data))
+ return fail(ctx, "Protocol: format error", "pkt-line: format error "+fmt.Sprint(rs.Data))
}
if index < 0 {
if len(rs.Data) == 10 && rs.Data[9] == '\n' {
index = 9
} else {
- return fail("Internal Server Error", "pkt-line: format error "+fmt.Sprint(rs.Data))
+ return fail(ctx, "Protocol: format error", "pkt-line: format error "+fmt.Sprint(rs.Data))
}
}
if string(rs.Data[0:index]) != VersionHead {
- return fail("Internal Server Error", "Received unsupported version: %s", string(rs.Data[0:index]))
+ return fail(ctx, "Protocol: version error", "Received unsupported version: %s", string(rs.Data[0:index]))
}
requestOptions = strings.Split(string(rs.Data[index+1:]), " ")
@@ -555,17 +547,17 @@ Gitea or set your environment appropriately.`, "")
}
response = append(response, '\n')
- _, err = readPktLine(reader, pktLineTypeFlush)
+ _, err = readPktLine(ctx, reader, pktLineTypeFlush)
if err != nil {
return err
}
- err = writeDataPktLine(os.Stdout, response)
+ err = writeDataPktLine(ctx, os.Stdout, response)
if err != nil {
return err
}
- err = writeFlushPktLine(os.Stdout)
+ err = writeFlushPktLine(ctx, os.Stdout)
if err != nil {
return err
}
@@ -588,7 +580,7 @@ Gitea or set your environment appropriately.`, "")
for {
// note: pktLineTypeUnknow means pktLineTypeFlush and pktLineTypeData all allowed
- rs, err = readPktLine(reader, pktLineTypeUnknow)
+ rs, err = readPktLine(ctx, reader, pktLineTypeUnknow)
if err != nil {
return err
}
@@ -609,7 +601,7 @@ Gitea or set your environment appropriately.`, "")
if hasPushOptions {
for {
- rs, err = readPktLine(reader, pktLineTypeUnknow)
+ rs, err = readPktLine(ctx, reader, pktLineTypeUnknow)
if err != nil {
return err
}
@@ -626,9 +618,9 @@ Gitea or set your environment appropriately.`, "")
}
// 3. run hook
- resp, err := private.HookProcReceive(ctx, repoUser, repoName, hookOptions)
- if err != nil {
- return fail("Internal Server Error", "run proc-receive hook failed :%v", err)
+ resp, extra := private.HookProcReceive(ctx, repoUser, repoName, hookOptions)
+ if extra.HasError() {
+ return fail(ctx, extra.UserMsg, "HookProcReceive failed: %v", extra.Error)
}
// 4. response result to service
@@ -649,7 +641,7 @@ Gitea or set your environment appropriately.`, "")
for _, rs := range resp.Results {
if len(rs.Err) > 0 {
- err = writeDataPktLine(os.Stdout, []byte("ng "+rs.OriginalRef+" "+rs.Err))
+ err = writeDataPktLine(ctx, os.Stdout, []byte("ng "+rs.OriginalRef+" "+rs.Err))
if err != nil {
return err
}
@@ -657,43 +649,43 @@ Gitea or set your environment appropriately.`, "")
}
if rs.IsNotMatched {
- err = writeDataPktLine(os.Stdout, []byte("ok "+rs.OriginalRef))
+ err = writeDataPktLine(ctx, os.Stdout, []byte("ok "+rs.OriginalRef))
if err != nil {
return err
}
- err = writeDataPktLine(os.Stdout, []byte("option fall-through"))
+ err = writeDataPktLine(ctx, os.Stdout, []byte("option fall-through"))
if err != nil {
return err
}
continue
}
- err = writeDataPktLine(os.Stdout, []byte("ok "+rs.OriginalRef))
+ err = writeDataPktLine(ctx, os.Stdout, []byte("ok "+rs.OriginalRef))
if err != nil {
return err
}
- err = writeDataPktLine(os.Stdout, []byte("option refname "+rs.Ref))
+ err = writeDataPktLine(ctx, os.Stdout, []byte("option refname "+rs.Ref))
if err != nil {
return err
}
if rs.OldOID != git.EmptySHA {
- err = writeDataPktLine(os.Stdout, []byte("option old-oid "+rs.OldOID))
+ err = writeDataPktLine(ctx, os.Stdout, []byte("option old-oid "+rs.OldOID))
if err != nil {
return err
}
}
- err = writeDataPktLine(os.Stdout, []byte("option new-oid "+rs.NewOID))
+ err = writeDataPktLine(ctx, os.Stdout, []byte("option new-oid "+rs.NewOID))
if err != nil {
return err
}
if rs.IsForcePush {
- err = writeDataPktLine(os.Stdout, []byte("option forced-update"))
+ err = writeDataPktLine(ctx, os.Stdout, []byte("option forced-update"))
if err != nil {
return err
}
}
}
- err = writeFlushPktLine(os.Stdout)
+ err = writeFlushPktLine(ctx, os.Stdout)
return err
}
@@ -718,7 +710,7 @@ type gitPktLine struct {
Data []byte
}
-func readPktLine(in *bufio.Reader, requestType pktLineType) (*gitPktLine, error) {
+func readPktLine(ctx context.Context, in *bufio.Reader, requestType pktLineType) (*gitPktLine, error) {
var (
err error
r *gitPktLine
@@ -729,33 +721,33 @@ func readPktLine(in *bufio.Reader, requestType pktLineType) (*gitPktLine, error)
for i := 0; i < 4; i++ {
lengthBytes[i], err = in.ReadByte()
if err != nil {
- return nil, fail("Internal Server Error", "Pkt-Line: read stdin failed : %v", err)
+ return nil, fail(ctx, "Protocol: stdin error", "Pkt-Line: read stdin failed : %v", err)
}
}
r = new(gitPktLine)
r.Length, err = strconv.ParseUint(string(lengthBytes), 16, 32)
if err != nil {
- return nil, fail("Internal Server Error", "Pkt-Line format is wrong :%v", err)
+ return nil, fail(ctx, "Protocol: format parse error", "Pkt-Line format is wrong :%v", err)
}
if r.Length == 0 {
if requestType == pktLineTypeData {
- return nil, fail("Internal Server Error", "Pkt-Line format is wrong")
+ return nil, fail(ctx, "Protocol: format data error", "Pkt-Line format is wrong")
}
r.Type = pktLineTypeFlush
return r, nil
}
if r.Length <= 4 || r.Length > 65520 || requestType == pktLineTypeFlush {
- return nil, fail("Internal Server Error", "Pkt-Line format is wrong")
+ return nil, fail(ctx, "Protocol: format length error", "Pkt-Line format is wrong")
}
r.Data = make([]byte, r.Length-4)
for i := range r.Data {
r.Data[i], err = in.ReadByte()
if err != nil {
- return nil, fail("Internal Server Error", "Pkt-Line: read stdin failed : %v", err)
+ return nil, fail(ctx, "Protocol: data error", "Pkt-Line: read stdin failed : %v", err)
}
}
@@ -764,19 +756,15 @@ func readPktLine(in *bufio.Reader, requestType pktLineType) (*gitPktLine, error)
return r, nil
}
-func writeFlushPktLine(out io.Writer) error {
+func writeFlushPktLine(ctx context.Context, out io.Writer) error {
l, err := out.Write([]byte("0000"))
- if err != nil {
- return fail("Internal Server Error", "Pkt-Line response failed: %v", err)
+ if err != nil || l != 4 {
+ return fail(ctx, "Protocol: write error", "Pkt-Line response failed: %v", err)
}
- if l != 4 {
- return fail("Internal Server Error", "Pkt-Line response failed: %v", err)
- }
-
return nil
}
-func writeDataPktLine(out io.Writer, data []byte) error {
+func writeDataPktLine(ctx context.Context, out io.Writer, data []byte) error {
hexchar := []byte("0123456789abcdef")
hex := func(n uint64) byte {
return hexchar[(n)&15]
@@ -790,19 +778,13 @@ func writeDataPktLine(out io.Writer, data []byte) error {
tmp[3] = hex(length)
lr, err := out.Write(tmp)
- if err != nil {
- return fail("Internal Server Error", "Pkt-Line response failed: %v", err)
- }
- if lr != 4 {
- return fail("Internal Server Error", "Pkt-Line response failed: %v", err)
+ if err != nil || lr != 4 {
+ return fail(ctx, "Protocol: write error", "Pkt-Line response failed: %v", err)
}
lr, err = out.Write(data)
- if err != nil {
- return fail("Internal Server Error", "Pkt-Line response failed: %v", err)
- }
- if int(length-4) != lr {
- return fail("Internal Server Error", "Pkt-Line response failed: %v", err)
+ if err != nil || int(length-4) != lr {
+ return fail(ctx, "Protocol: write error", "Pkt-Line response failed: %v", err)
}
return nil
diff --git a/cmd/hook_test.go b/cmd/hook_test.go
index fe1f072a6f..91f24ff2b4 100644
--- a/cmd/hook_test.go
+++ b/cmd/hook_test.go
@@ -6,6 +6,7 @@ package cmd
import (
"bufio"
"bytes"
+ "context"
"strings"
"testing"
@@ -14,27 +15,28 @@ import (
func TestPktLine(t *testing.T) {
// test read
+ ctx := context.Background()
s := strings.NewReader("0000")
r := bufio.NewReader(s)
- result, err := readPktLine(r, pktLineTypeFlush)
+ result, err := readPktLine(ctx, r, pktLineTypeFlush)
assert.NoError(t, err)
assert.Equal(t, pktLineTypeFlush, result.Type)
s = strings.NewReader("0006a\n")
r = bufio.NewReader(s)
- result, err = readPktLine(r, pktLineTypeData)
+ result, err = readPktLine(ctx, r, pktLineTypeData)
assert.NoError(t, err)
assert.Equal(t, pktLineTypeData, result.Type)
assert.Equal(t, []byte("a\n"), result.Data)
// test write
w := bytes.NewBuffer([]byte{})
- err = writeFlushPktLine(w)
+ err = writeFlushPktLine(ctx, w)
assert.NoError(t, err)
assert.Equal(t, []byte("0000"), w.Bytes())
w.Reset()
- err = writeDataPktLine(w, []byte("a\nb"))
+ err = writeDataPktLine(ctx, w, []byte("a\nb"))
assert.NoError(t, err)
assert.Equal(t, []byte("0007a\nb"), w.Bytes())
}
diff --git a/cmd/keys.go b/cmd/keys.go
index 74dc1cc68c..deb94fca5d 100644
--- a/cmd/keys.go
+++ b/cmd/keys.go
@@ -64,11 +64,12 @@ func runKeys(c *cli.Context) error {
ctx, cancel := installSignals()
defer cancel()
- setup("keys.log", false)
+ setup(ctx, false)
- authorizedString, err := private.AuthorizedPublicKeyByContent(ctx, content)
- if err != nil {
- return err
+ authorizedString, extra := private.AuthorizedPublicKeyByContent(ctx, content)
+ // do not use handleCliResponseExtra or cli.NewExitError, if it exists immediately, it breaks some tests like Test_CmdKeys
+ if extra.Error != nil {
+ return extra.Error
}
fmt.Println(strings.TrimSpace(authorizedString))
return nil
diff --git a/cmd/mailer.go b/cmd/mailer.go
index d05fee12bc..50ba4b4741 100644
--- a/cmd/mailer.go
+++ b/cmd/mailer.go
@@ -5,7 +5,6 @@ package cmd
import (
"fmt"
- "net/http"
"code.gitea.io/gitea/modules/private"
"code.gitea.io/gitea/modules/setting"
@@ -43,13 +42,10 @@ func runSendMail(c *cli.Context) error {
}
}
- status, message := private.SendEmail(ctx, subject, body, nil)
- if status != http.StatusOK {
- fmt.Printf("error: %s\n", message)
- return nil
+ respText, extra := private.SendEmail(ctx, subject, body, nil)
+ if extra.HasError() {
+ return handleCliResponseExtra(extra)
}
-
- fmt.Printf("Success: %s\n", message)
-
+ _, _ = fmt.Printf("Sent %s email(s) to all users\n", respText)
return nil
}
diff --git a/cmd/manager.go b/cmd/manager.go
index cdfe509075..3f1e223190 100644
--- a/cmd/manager.go
+++ b/cmd/manager.go
@@ -4,8 +4,6 @@
package cmd
import (
- "fmt"
- "net/http"
"os"
"time"
@@ -103,57 +101,34 @@ func runShutdown(c *cli.Context) error {
ctx, cancel := installSignals()
defer cancel()
- setup("manager", c.Bool("debug"))
- statusCode, msg := private.Shutdown(ctx)
- switch statusCode {
- case http.StatusInternalServerError:
- return fail("InternalServerError", msg)
- }
-
- fmt.Fprintln(os.Stdout, msg)
- return nil
+ setup(ctx, c.Bool("debug"))
+ extra := private.Shutdown(ctx)
+ return handleCliResponseExtra(extra)
}
func runRestart(c *cli.Context) error {
ctx, cancel := installSignals()
defer cancel()
- setup("manager", c.Bool("debug"))
- statusCode, msg := private.Restart(ctx)
- switch statusCode {
- case http.StatusInternalServerError:
- return fail("InternalServerError", msg)
- }
-
- fmt.Fprintln(os.Stdout, msg)
- return nil
+ setup(ctx, c.Bool("debug"))
+ extra := private.Restart(ctx)
+ return handleCliResponseExtra(extra)
}
func runFlushQueues(c *cli.Context) error {
ctx, cancel := installSignals()
defer cancel()
- setup("manager", c.Bool("debug"))
- statusCode, msg := private.FlushQueues(ctx, c.Duration("timeout"), c.Bool("non-blocking"))
- switch statusCode {
- case http.StatusInternalServerError:
- return fail("InternalServerError", msg)
- }
-
- fmt.Fprintln(os.Stdout, msg)
- return nil
+ setup(ctx, c.Bool("debug"))
+ extra := private.FlushQueues(ctx, c.Duration("timeout"), c.Bool("non-blocking"))
+ return handleCliResponseExtra(extra)
}
func runProcesses(c *cli.Context) error {
ctx, cancel := installSignals()
defer cancel()
- setup("manager", c.Bool("debug"))
- statusCode, msg := private.Processes(ctx, os.Stdout, c.Bool("flat"), c.Bool("no-system"), c.Bool("stacktraces"), c.Bool("json"), c.String("cancel"))
- switch statusCode {
- case http.StatusInternalServerError:
- return fail("InternalServerError", msg)
- }
-
- return nil
+ setup(ctx, c.Bool("debug"))
+ extra := private.Processes(ctx, os.Stdout, c.Bool("flat"), c.Bool("no-system"), c.Bool("stacktraces"), c.Bool("json"), c.String("cancel"))
+ return handleCliResponseExtra(extra)
}
diff --git a/cmd/manager_logging.go b/cmd/manager_logging.go
index d49675ce87..914210d370 100644
--- a/cmd/manager_logging.go
+++ b/cmd/manager_logging.go
@@ -5,7 +5,6 @@ package cmd
import (
"fmt"
- "net/http"
"os"
"code.gitea.io/gitea/modules/log"
@@ -191,27 +190,25 @@ var (
)
func runRemoveLogger(c *cli.Context) error {
- setup("manager", c.Bool("debug"))
+ ctx, cancel := installSignals()
+ defer cancel()
+
+ setup(ctx, c.Bool("debug"))
group := c.String("group")
if len(group) == 0 {
group = log.DEFAULT
}
name := c.Args().First()
- ctx, cancel := installSignals()
- defer cancel()
-
- statusCode, msg := private.RemoveLogger(ctx, group, name)
- switch statusCode {
- case http.StatusInternalServerError:
- return fail("InternalServerError", msg)
- }
- fmt.Fprintln(os.Stdout, msg)
- return nil
+ extra := private.RemoveLogger(ctx, group, name)
+ return handleCliResponseExtra(extra)
}
func runAddSMTPLogger(c *cli.Context) error {
- setup("manager", c.Bool("debug"))
+ ctx, cancel := installSignals()
+ defer cancel()
+
+ setup(ctx, c.Bool("debug"))
vals := map[string]interface{}{}
mode := "smtp"
if c.IsSet("host") {
@@ -242,7 +239,10 @@ func runAddSMTPLogger(c *cli.Context) error {
}
func runAddConnLogger(c *cli.Context) error {
- setup("manager", c.Bool("debug"))
+ ctx, cancel := installSignals()
+ defer cancel()
+
+ setup(ctx, c.Bool("debug"))
vals := map[string]interface{}{}
mode := "conn"
vals["net"] = "tcp"
@@ -269,7 +269,10 @@ func runAddConnLogger(c *cli.Context) error {
}
func runAddFileLogger(c *cli.Context) error {
- setup("manager", c.Bool("debug"))
+ ctx, cancel := installSignals()
+ defer cancel()
+
+ setup(ctx, c.Bool("debug"))
vals := map[string]interface{}{}
mode := "file"
if c.IsSet("filename") {
@@ -299,7 +302,10 @@ func runAddFileLogger(c *cli.Context) error {
}
func runAddConsoleLogger(c *cli.Context) error {
- setup("manager", c.Bool("debug"))
+ ctx, cancel := installSignals()
+ defer cancel()
+
+ setup(ctx, c.Bool("debug"))
vals := map[string]interface{}{}
mode := "console"
if c.IsSet("stderr") && c.Bool("stderr") {
@@ -338,28 +344,17 @@ func commonAddLogger(c *cli.Context, mode string, vals map[string]interface{}) e
ctx, cancel := installSignals()
defer cancel()
- statusCode, msg := private.AddLogger(ctx, group, name, mode, vals)
- switch statusCode {
- case http.StatusInternalServerError:
- return fail("InternalServerError", msg)
- }
-
- fmt.Fprintln(os.Stdout, msg)
- return nil
+ extra := private.AddLogger(ctx, group, name, mode, vals)
+ return handleCliResponseExtra(extra)
}
func runPauseLogging(c *cli.Context) error {
ctx, cancel := installSignals()
defer cancel()
- setup("manager", c.Bool("debug"))
- statusCode, msg := private.PauseLogging(ctx)
- switch statusCode {
- case http.StatusInternalServerError:
- return fail("InternalServerError", msg)
- }
-
- fmt.Fprintln(os.Stdout, msg)
+ setup(ctx, c.Bool("debug"))
+ userMsg := private.PauseLogging(ctx)
+ _, _ = fmt.Fprintln(os.Stdout, userMsg)
return nil
}
@@ -367,14 +362,9 @@ func runResumeLogging(c *cli.Context) error {
ctx, cancel := installSignals()
defer cancel()
- setup("manager", c.Bool("debug"))
- statusCode, msg := private.ResumeLogging(ctx)
- switch statusCode {
- case http.StatusInternalServerError:
- return fail("InternalServerError", msg)
- }
-
- fmt.Fprintln(os.Stdout, msg)
+ setup(ctx, c.Bool("debug"))
+ userMsg := private.ResumeLogging(ctx)
+ _, _ = fmt.Fprintln(os.Stdout, userMsg)
return nil
}
@@ -382,28 +372,17 @@ func runReleaseReopenLogging(c *cli.Context) error {
ctx, cancel := installSignals()
defer cancel()
- setup("manager", c.Bool("debug"))
- statusCode, msg := private.ReleaseReopenLogging(ctx)
- switch statusCode {
- case http.StatusInternalServerError:
- return fail("InternalServerError", msg)
- }
-
- fmt.Fprintln(os.Stdout, msg)
+ setup(ctx, c.Bool("debug"))
+ userMsg := private.ReleaseReopenLogging(ctx)
+ _, _ = fmt.Fprintln(os.Stdout, userMsg)
return nil
}
func runSetLogSQL(c *cli.Context) error {
ctx, cancel := installSignals()
defer cancel()
- setup("manager", c.Bool("debug"))
-
- statusCode, msg := private.SetLogSQL(ctx, !c.Bool("off"))
- switch statusCode {
- case http.StatusInternalServerError:
- return fail("InternalServerError", msg)
- }
+ setup(ctx, c.Bool("debug"))
- fmt.Fprintln(os.Stdout, msg)
- return nil
+ extra := private.SetLogSQL(ctx, !c.Bool("off"))
+ return handleCliResponseExtra(extra)
}
diff --git a/cmd/restore_repo.go b/cmd/restore_repo.go
index c7dff41966..887b59bba9 100644
--- a/cmd/restore_repo.go
+++ b/cmd/restore_repo.go
@@ -4,11 +4,8 @@
package cmd
import (
- "errors"
- "net/http"
"strings"
- "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/private"
"code.gitea.io/gitea/modules/setting"
@@ -60,7 +57,7 @@ func runRestoreRepository(c *cli.Context) error {
if s := c.String("units"); s != "" {
units = strings.Split(s, ",")
}
- statusCode, errStr := private.RestoreRepo(
+ extra := private.RestoreRepo(
ctx,
c.String("repo_dir"),
c.String("owner_name"),
@@ -68,10 +65,5 @@ func runRestoreRepository(c *cli.Context) error {
units,
c.Bool("validation"),
)
- if statusCode == http.StatusOK {
- return nil
- }
-
- log.Fatal("Failed to restore repository: %v", errStr)
- return errors.New(errStr)
+ return handleCliResponseExtra(extra)
}
diff --git a/cmd/serv.go b/cmd/serv.go
index d7510845a5..72eb637071 100644
--- a/cmd/serv.go
+++ b/cmd/serv.go
@@ -7,7 +7,6 @@ package cmd
import (
"context"
"fmt"
- "net/http"
"net/url"
"os"
"os/exec"
@@ -16,6 +15,7 @@ import (
"strconv"
"strings"
"time"
+ "unicode"
asymkey_model "code.gitea.io/gitea/models/asymkey"
git_model "code.gitea.io/gitea/models/git"
@@ -55,7 +55,7 @@ var CmdServ = cli.Command{
},
}
-func setup(logPath string, debug bool) {
+func setup(ctx context.Context, debug bool) {
_ = log.DelLogger("console")
if debug {
_ = log.NewLogger(1000, "console", "console", `{"level":"trace","stacktracelevel":"NONE","stderr":true}`)
@@ -72,15 +72,15 @@ func setup(logPath string, debug bool) {
// `[repository]` `ROOT` is a relative path and $GITEA_WORK_DIR isn't passed to the SSH connection.
if _, err := os.Stat(setting.RepoRootPath); err != nil {
if os.IsNotExist(err) {
- _ = fail("Incorrect configuration, no repository directory.", "Directory `[repository].ROOT` %q was not found, please check if $GITEA_WORK_DIR is passed to the SSH connection or make `[repository].ROOT` an absolute value.", setting.RepoRootPath)
+ _ = fail(ctx, "Incorrect configuration, no repository directory.", "Directory `[repository].ROOT` %q was not found, please check if $GITEA_WORK_DIR is passed to the SSH connection or make `[repository].ROOT` an absolute value.", setting.RepoRootPath)
} else {
- _ = fail("Incorrect configuration, repository directory is inaccessible", "Directory `[repository].ROOT` %q is inaccessible. err: %v", setting.RepoRootPath, err)
+ _ = fail(ctx, "Incorrect configuration, repository directory is inaccessible", "Directory `[repository].ROOT` %q is inaccessible. err: %v", setting.RepoRootPath, err)
}
return
}
if err := git.InitSimple(context.Background()); err != nil {
- _ = fail("Failed to init git", "Failed to init git, err: %v", err)
+ _ = fail(ctx, "Failed to init git", "Failed to init git, err: %v", err)
}
}
@@ -94,24 +94,46 @@ var (
alphaDashDotPattern = regexp.MustCompile(`[^\w-\.]`)
)
-func fail(userMessage, logMessage string, args ...interface{}) error {
+// fail prints message to stdout, it's mainly used for git serv and git hook commands.
+// The output will be passed to git client and shown to user.
+func fail(ctx context.Context, userMessage, logMsgFmt string, args ...interface{}) error {
+ if userMessage == "" {
+ userMessage = "Internal Server Error (no specific error)"
+ }
+
// There appears to be a chance to cause a zombie process and failure to read the Exit status
// if nothing is outputted on stdout.
_, _ = fmt.Fprintln(os.Stdout, "")
_, _ = fmt.Fprintln(os.Stderr, "Gitea:", userMessage)
- if len(logMessage) > 0 {
+ if logMsgFmt != "" {
+ logMsg := fmt.Sprintf(logMsgFmt, args...)
if !setting.IsProd {
- _, _ = fmt.Fprintf(os.Stderr, logMessage+"\n", args...)
+ _, _ = fmt.Fprintln(os.Stderr, "Gitea:", logMsg)
+ }
+ if userMessage != "" {
+ if unicode.IsPunct(rune(userMessage[len(userMessage)-1])) {
+ logMsg = userMessage + " " + logMsg
+ } else {
+ logMsg = userMessage + ". " + logMsg
+ }
}
+ _ = private.SSHLog(ctx, true, logMsg)
}
- ctx, cancel := installSignals()
- defer cancel()
+ return cli.NewExitError("", 1)
+}
- if len(logMessage) > 0 {
- _ = private.SSHLog(ctx, true, fmt.Sprintf(logMessage+": ", args...))
+// handleCliResponseExtra handles the extra response from the cli sub-commands
+// If there is a user message it will be printed to stdout
+// If the command failed it will return an error (the error will be printed by cli framework)
+func handleCliResponseExtra(extra private.ResponseExtra) error {
+ if extra.UserMsg != "" {
+ _, _ = fmt.Fprintln(os.Stdout, extra.UserMsg)
}
- return cli.NewExitError("", 1)
+ if extra.HasError() {
+ return cli.NewExitError(extra.Error, 1)
+ }
+ return nil
}
func runServ(c *cli.Context) error {
@@ -119,7 +141,7 @@ func runServ(c *cli.Context) error {
defer cancel()
// FIXME: This needs to internationalised
- setup("serv.log", c.Bool("debug"))
+ setup(ctx, c.Bool("debug"))
if setting.SSH.Disabled {
println("Gitea: SSH has been disabled")
@@ -135,18 +157,18 @@ func runServ(c *cli.Context) error {
keys := strings.Split(c.Args()[0], "-")
if len(keys) != 2 || keys[0] != "key" {
- return fail("Key ID format error", "Invalid key argument: %s", c.Args()[0])
+ return fail(ctx, "Key ID format error", "Invalid key argument: %s", c.Args()[0])
}
keyID, err := strconv.ParseInt(keys[1], 10, 64)
if err != nil {
- return fail("Key ID format error", "Invalid key argument: %s", c.Args()[1])
+ return fail(ctx, "Key ID parsing error", "Invalid key argument: %s", c.Args()[1])
}
cmd := os.Getenv("SSH_ORIGINAL_COMMAND")
if len(cmd) == 0 {
key, user, err := private.ServNoCommand(ctx, keyID)
if err != nil {
- return fail("Internal error", "Failed to check provided key: %v", err)
+ return fail(ctx, "Key check failed", "Failed to check provided key: %v", err)
}
switch key.Type {
case asymkey_model.KeyTypeDeploy:
@@ -164,7 +186,7 @@ func runServ(c *cli.Context) error {
words, err := shellquote.Split(cmd)
if err != nil {
- return fail("Error parsing arguments", "Failed to parse arguments: %v", err)
+ return fail(ctx, "Error parsing arguments", "Failed to parse arguments: %v", err)
}
if len(words) < 2 {
@@ -175,7 +197,7 @@ func runServ(c *cli.Context) error {
return nil
}
}
- return fail("Too few arguments", "Too few arguments in cmd: %s", cmd)
+ return fail(ctx, "Too few arguments", "Too few arguments in cmd: %s", cmd)
}
verb := words[0]
@@ -187,7 +209,7 @@ func runServ(c *cli.Context) error {
var lfsVerb string
if verb == lfsAuthenticateVerb {
if !setting.LFS.StartServer {
- return fail("Unknown git command", "LFS authentication request over SSH denied, LFS support is disabled")
+ return fail(ctx, "Unknown git command", "LFS authentication request over SSH denied, LFS support is disabled")
}
if len(words) > 2 {
@@ -200,37 +222,37 @@ func runServ(c *cli.Context) error {
rr := strings.SplitN(repoPath, "/", 2)
if len(rr) != 2 {
- return fail("Invalid repository path", "Invalid repository path: %v", repoPath)
+ return fail(ctx, "Invalid repository path", "Invalid repository path: %v", repoPath)
}
username := strings.ToLower(rr[0])
reponame := strings.ToLower(strings.TrimSuffix(rr[1], ".git"))
if alphaDashDotPattern.MatchString(reponame) {
- return fail("Invalid repo name", "Invalid repo name: %s", reponame)
+ return fail(ctx, "Invalid repo name", "Invalid repo name: %s", reponame)
}
if c.Bool("enable-pprof") {
if err := os.MkdirAll(setting.PprofDataPath, os.ModePerm); err != nil {
- return fail("Error while trying to create PPROF_DATA_PATH", "Error while trying to create PPROF_DATA_PATH: %v", err)
+ return fail(ctx, "Error while trying to create PPROF_DATA_PATH", "Error while trying to create PPROF_DATA_PATH: %v", err)
}
stopCPUProfiler, err := pprof.DumpCPUProfileForUsername(setting.PprofDataPath, username)
if err != nil {
- return fail("Internal Server Error", "Unable to start CPU profile: %v", err)
+ return fail(ctx, "Unable to start CPU profiler", "Unable to start CPU profile: %v", err)
}
defer func() {
stopCPUProfiler()
err := pprof.DumpMemProfileForUsername(setting.PprofDataPath, username)
if err != nil {
- _ = fail("Internal Server Error", "Unable to dump Mem Profile: %v", err)
+ _ = fail(ctx, "Unable to dump Mem profile", "Unable to dump Mem Profile: %v", err)
}
}()
}
requestedMode, has := allowedCommands[verb]
if !has {
- return fail("Unknown git command", "Unknown git command %s", verb)
+ return fail(ctx, "Unknown git command", "Unknown git command %s", verb)
}
if verb == lfsAuthenticateVerb {
@@ -239,20 +261,13 @@ func runServ(c *cli.Context) error {
} else if lfsVerb == "download" {
requestedMode = perm.AccessModeRead
} else {
- return fail("Unknown LFS verb", "Unknown lfs verb %s", lfsVerb)
+ return fail(ctx, "Unknown LFS verb", "Unknown lfs verb %s", lfsVerb)
}
}
- results, err := private.ServCommand(ctx, keyID, username, reponame, requestedMode, verb, lfsVerb)
- if err != nil {
- if private.IsErrServCommand(err) {
- errServCommand := err.(private.ErrServCommand)
- if errServCommand.StatusCode != http.StatusInternalServerError {
- return fail("Unauthorized", "%s", errServCommand.Error())
- }
- return fail("Internal Server Error", "%s", errServCommand.Error())
- }
- return fail("Internal Server Error", "%s", err.Error())
+ results, extra := private.ServCommand(ctx, keyID, username, reponame, requestedMode, verb, lfsVerb)
+ if extra.HasError() {
+ return fail(ctx, extra.UserMsg, "ServCommand failed: %s", extra.Error)
}
// LFS token authentication
@@ -274,7 +289,7 @@ func runServ(c *cli.Context) error {
// Sign and get the complete encoded token as a string using the secret
tokenString, err := token.SignedString(setting.LFS.JWTSecretBytes)
if err != nil {
- return fail("Internal error", "Failed to sign JWT token: %v", err)
+ return fail(ctx, "Failed to sign JWT Token", "Failed to sign JWT token: %v", err)
}
tokenAuthentication := &git_model.LFSTokenResponse{
@@ -286,7 +301,7 @@ func runServ(c *cli.Context) error {
enc := json.NewEncoder(os.Stdout)
err = enc.Encode(tokenAuthentication)
if err != nil {
- return fail("Internal error", "Failed to encode LFS json response: %v", err)
+ return fail(ctx, "Failed to encode LFS json response", "Failed to encode LFS json response: %v", err)
}
return nil
}
@@ -332,13 +347,13 @@ func runServ(c *cli.Context) error {
gitcmd.Env = append(gitcmd.Env, git.CommonCmdServEnvs()...)
if err = gitcmd.Run(); err != nil {
- return fail("Internal error", "Failed to execute git command: %v", err)
+ return fail(ctx, "Failed to execute git command", "Failed to execute git command: %v", err)
}
// Update user key activity.
if results.KeyID > 0 {
if err = private.UpdatePublicKeyInRepo(ctx, results.KeyID, results.RepoID); err != nil {
- return fail("Internal error", "UpdatePublicKeyInRepo: %v", err)
+ return fail(ctx, "Failed to update public key", "UpdatePublicKeyInRepo: %v", err)
}
}
diff --git a/modules/httplib/httplib.go b/modules/httplib/httplib.go
index a1984400d6..e904d77e14 100644
--- a/modules/httplib/httplib.go
+++ b/modules/httplib/httplib.go
@@ -8,6 +8,7 @@ import (
"bytes"
"context"
"crypto/tls"
+ "fmt"
"io"
"net"
"net/http"
@@ -68,6 +69,11 @@ func (r *Request) SetTimeout(connectTimeout, readWriteTimeout time.Duration) *Re
return r
}
+func (r *Request) SetReadWriteTimeout(readWriteTimeout time.Duration) *Request {
+ r.setting.ReadWriteTimeout = readWriteTimeout
+ return r
+}
+
// SetTLSClientConfig sets tls connection configurations if visiting https url.
func (r *Request) SetTLSClientConfig(config *tls.Config) *Request {
r.setting.TLSClientConfig = config
@@ -138,11 +144,11 @@ func (r *Request) getResponse() (*http.Response, error) {
r.Body(paramBody)
}
- url, err := url.Parse(r.url)
+ var err error
+ r.req.URL, err = url.Parse(r.url)
if err != nil {
return nil, err
}
- r.req.URL = url
trans := r.setting.Transport
if trans == nil {
@@ -194,3 +200,7 @@ func TimeoutDialer(cTimeout time.Duration) func(ctx context.Context, net, addr s
return conn, nil
}
}
+
+func (r *Request) GoString() string {
+ return fmt.Sprintf("%s %s", r.req.Method, r.url)
+}
diff --git a/modules/private/hook.go b/modules/private/hook.go
index 9533eaae59..0563e4d80a 100644
--- a/modules/private/hook.go
+++ b/modules/private/hook.go
@@ -5,14 +5,11 @@ package private
import (
"context"
- "errors"
"fmt"
- "net/http"
"net/url"
"strconv"
"time"
- "code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/setting"
)
@@ -99,126 +96,46 @@ type HookProcReceiveRefResult struct {
}
// HookPreReceive check whether the provided commits are allowed
-func HookPreReceive(ctx context.Context, ownerName, repoName string, opts HookOptions) (int, string) {
- reqURL := setting.LocalURL + fmt.Sprintf("api/internal/hook/pre-receive/%s/%s",
- url.PathEscape(ownerName),
- url.PathEscape(repoName),
- )
- req := newInternalRequest(ctx, reqURL, "POST")
- req = req.Header("Content-Type", "application/json")
- jsonBytes, _ := json.Marshal(opts)
- req.Body(jsonBytes)
- req.SetTimeout(60*time.Second, time.Duration(60+len(opts.OldCommitIDs))*time.Second)
- resp, err := req.Response()
- if err != nil {
- return http.StatusInternalServerError, fmt.Sprintf("Unable to contact gitea: %v", err.Error())
- }
- defer resp.Body.Close()
-
- if resp.StatusCode != http.StatusOK {
- return resp.StatusCode, decodeJSONError(resp).Err
- }
-
- return http.StatusOK, ""
+func HookPreReceive(ctx context.Context, ownerName, repoName string, opts HookOptions) ResponseExtra {
+ reqURL := setting.LocalURL + fmt.Sprintf("api/internal/hook/pre-receive/%s/%s", url.PathEscape(ownerName), url.PathEscape(repoName))
+ req := newInternalRequest(ctx, reqURL, "POST", opts)
+ req.SetReadWriteTimeout(time.Duration(60+len(opts.OldCommitIDs)) * time.Second)
+ _, extra := requestJSONResp(req, &responseText{})
+ return extra
}
// HookPostReceive updates services and users
-func HookPostReceive(ctx context.Context, ownerName, repoName string, opts HookOptions) (*HookPostReceiveResult, string) {
- reqURL := setting.LocalURL + fmt.Sprintf("api/internal/hook/post-receive/%s/%s",
- url.PathEscape(ownerName),
- url.PathEscape(repoName),
- )
-
- req := newInternalRequest(ctx, reqURL, "POST")
- req = req.Header("Content-Type", "application/json")
- req.SetTimeout(60*time.Second, time.Duration(60+len(opts.OldCommitIDs))*time.Second)
- jsonBytes, _ := json.Marshal(opts)
- req.Body(jsonBytes)
- resp, err := req.Response()
- if err != nil {
- return nil, fmt.Sprintf("Unable to contact gitea: %v", err.Error())
- }
- defer resp.Body.Close()
-
- if resp.StatusCode != http.StatusOK {
- return nil, decodeJSONError(resp).Err
- }
- res := &HookPostReceiveResult{}
- _ = json.NewDecoder(resp.Body).Decode(res)
-
- return res, ""
+func HookPostReceive(ctx context.Context, ownerName, repoName string, opts HookOptions) (*HookPostReceiveResult, ResponseExtra) {
+ reqURL := setting.LocalURL + fmt.Sprintf("api/internal/hook/post-receive/%s/%s", url.PathEscape(ownerName), url.PathEscape(repoName))
+ req := newInternalRequest(ctx, reqURL, "POST", opts)
+ req.SetReadWriteTimeout(time.Duration(60+len(opts.OldCommitIDs)) * time.Second)
+ return requestJSONResp(req, &HookPostReceiveResult{})
}
// HookProcReceive proc-receive hook
-func HookProcReceive(ctx context.Context, ownerName, repoName string, opts HookOptions) (*HookProcReceiveResult, error) {
- reqURL := setting.LocalURL + fmt.Sprintf("api/internal/hook/proc-receive/%s/%s",
- url.PathEscape(ownerName),
- url.PathEscape(repoName),
- )
-
- req := newInternalRequest(ctx, reqURL, "POST")
- req = req.Header("Content-Type", "application/json")
- req.SetTimeout(60*time.Second, time.Duration(60+len(opts.OldCommitIDs))*time.Second)
- jsonBytes, _ := json.Marshal(opts)
- req.Body(jsonBytes)
- resp, err := req.Response()
- if err != nil {
- return nil, fmt.Errorf("Unable to contact gitea: %w", err)
- }
- defer resp.Body.Close()
-
- if resp.StatusCode != http.StatusOK {
- return nil, errors.New(decodeJSONError(resp).Err)
- }
- res := &HookProcReceiveResult{}
- _ = json.NewDecoder(resp.Body).Decode(res)
+func HookProcReceive(ctx context.Context, ownerName, repoName string, opts HookOptions) (*HookProcReceiveResult, ResponseExtra) {
+ reqURL := setting.LocalURL + fmt.Sprintf("api/internal/hook/proc-receive/%s/%s", url.PathEscape(ownerName), url.PathEscape(repoName))
- return res, nil
+ req := newInternalRequest(ctx, reqURL, "POST", opts)
+ req.SetReadWriteTimeout(time.Duration(60+len(opts.OldCommitIDs)) * time.Second)
+ return requestJSONResp(req, &HookProcReceiveResult{})
}
// SetDefaultBranch will set the default branch to the provided branch for the provided repository
-func SetDefaultBranch(ctx context.Context, ownerName, repoName, branch string) error {
+func SetDefaultBranch(ctx context.Context, ownerName, repoName, branch string) ResponseExtra {
reqURL := setting.LocalURL + fmt.Sprintf("api/internal/hook/set-default-branch/%s/%s/%s",
url.PathEscape(ownerName),
url.PathEscape(repoName),
url.PathEscape(branch),
)
req := newInternalRequest(ctx, reqURL, "POST")
- req = req.Header("Content-Type", "application/json")
-
- req.SetTimeout(60*time.Second, 60*time.Second)
- resp, err := req.Response()
- if err != nil {
- return fmt.Errorf("Unable to contact gitea: %w", err)
- }
- defer resp.Body.Close()
- if resp.StatusCode != http.StatusOK {
- return fmt.Errorf("Error returned from gitea: %v", decodeJSONError(resp).Err)
- }
- return nil
+ return requestJSONUserMsg(req, "")
}
// SSHLog sends ssh error log response
func SSHLog(ctx context.Context, isErr bool, msg string) error {
reqURL := setting.LocalURL + "api/internal/ssh/log"
- req := newInternalRequest(ctx, reqURL, "POST")
- req = req.Header("Content-Type", "application/json")
-
- jsonBytes, _ := json.Marshal(&SSHLogOption{
- IsError: isErr,
- Message: msg,
- })
- req.Body(jsonBytes)
-
- req.SetTimeout(60*time.Second, 60*time.Second)
- resp, err := req.Response()
- if err != nil {
- return fmt.Errorf("unable to contact gitea: %w", err)
- }
-
- defer resp.Body.Close()
- if resp.StatusCode != http.StatusOK {
- return fmt.Errorf("Error returned from gitea: %v", decodeJSONError(resp).Err)
- }
- return nil
+ req := newInternalRequest(ctx, reqURL, "POST", &SSHLogOption{IsError: isErr, Message: msg})
+ _, extra := requestJSONResp(req, &responseText{})
+ return extra.Error
}
diff --git a/modules/private/internal.go b/modules/private/internal.go
index a8b62fdde7..9c330a24a8 100644
--- a/modules/private/internal.go
+++ b/modules/private/internal.go
@@ -11,6 +11,7 @@ import (
"net/http"
"os"
"strings"
+ "time"
"code.gitea.io/gitea/modules/httplib"
"code.gitea.io/gitea/modules/json"
@@ -19,29 +20,10 @@ import (
"code.gitea.io/gitea/modules/setting"
)
-func newRequest(ctx context.Context, url, method, sourceIP string) *httplib.Request {
- if setting.InternalToken == "" {
- log.Fatal(`The INTERNAL_TOKEN setting is missing from the configuration file: %q.
-Ensure you are running in the correct environment or set the correct configuration file with -c.`, setting.CustomConf)
- }
- return httplib.NewRequest(url, method).
- SetContext(ctx).
- Header("X-Real-IP", sourceIP).
- Header("Authorization", fmt.Sprintf("Bearer %s", setting.InternalToken))
-}
-
-// Response internal request response
+// Response is used for internal request response (for user message and error message)
type Response struct {
- Err string `json:"err"`
-}
-
-func decodeJSONError(resp *http.Response) *Response {
- var res Response
- err := json.NewDecoder(resp.Body).Decode(&res)
- if err != nil {
- res.Err = err.Error()
- }
- return &res
+ Err string `json:"err,omitempty"` // server-side error log message, it won't be exposed to end users
+ UserMsg string `json:"user_msg,omitempty"` // meaningful error message for end users, it will be shown in git client's output.
}
func getClientIP() string {
@@ -52,11 +34,21 @@ func getClientIP() string {
return strings.Fields(sshConnEnv)[0]
}
-func newInternalRequest(ctx context.Context, url, method string) *httplib.Request {
- req := newRequest(ctx, url, method, getClientIP()).SetTLSClientConfig(&tls.Config{
- InsecureSkipVerify: true,
- ServerName: setting.Domain,
- })
+func newInternalRequest(ctx context.Context, url, method string, body ...any) *httplib.Request {
+ if setting.InternalToken == "" {
+ log.Fatal(`The INTERNAL_TOKEN setting is missing from the configuration file: %q.
+Ensure you are running in the correct environment or set the correct configuration file with -c.`, setting.CustomConf)
+ }
+
+ req := httplib.NewRequest(url, method).
+ SetContext(ctx).
+ Header("X-Real-IP", getClientIP()).
+ Header("Authorization", fmt.Sprintf("Bearer %s", setting.InternalToken)).
+ SetTLSClientConfig(&tls.Config{
+ InsecureSkipVerify: true,
+ ServerName: setting.Domain,
+ })
+
if setting.Protocol == setting.HTTPUnix {
req.SetTransport(&http.Transport{
DialContext: func(ctx context.Context, _, _ string) (net.Conn, error) {
@@ -90,5 +82,15 @@ func newInternalRequest(ctx context.Context, url, method string) *httplib.Reques
},
})
}
+
+ if len(body) == 1 {
+ req.Header("Content-Type", "application/json")
+ jsonBytes, _ := json.Marshal(body[0])
+ req.Body(jsonBytes)
+ } else if len(body) > 1 {
+ log.Fatal("Too many arguments for newInternalRequest")
+ }
+
+ req.SetTimeout(10*time.Second, 60*time.Second)
return req
}
diff --git a/modules/private/key.go b/modules/private/key.go
index f09d6de2bf..6f7cd87796 100644
--- a/modules/private/key.go
+++ b/modules/private/key.go
@@ -6,8 +6,6 @@ package private
import (
"context"
"fmt"
- "io"
- "net/http"
"code.gitea.io/gitea/modules/setting"
)
@@ -16,39 +14,18 @@ import (
func UpdatePublicKeyInRepo(ctx context.Context, keyID, repoID int64) error {
// Ask for running deliver hook and test pull request tasks.
reqURL := setting.LocalURL + fmt.Sprintf("api/internal/ssh/%d/update/%d", keyID, repoID)
- resp, err := newInternalRequest(ctx, reqURL, "POST").Response()
- if err != nil {
- return err
- }
-
- defer resp.Body.Close()
-
- // All 2XX status codes are accepted and others will return an error
- if resp.StatusCode/100 != 2 {
- return fmt.Errorf("Failed to update public key: %s", decodeJSONError(resp).Err)
- }
- return nil
+ req := newInternalRequest(ctx, reqURL, "POST")
+ _, extra := requestJSONResp(req, &responseText{})
+ return extra.Error
}
// AuthorizedPublicKeyByContent searches content as prefix (leak e-mail part)
// and returns public key found.
-func AuthorizedPublicKeyByContent(ctx context.Context, content string) (string, error) {
+func AuthorizedPublicKeyByContent(ctx context.Context, content string) (string, ResponseExtra) {
// Ask for running deliver hook and test pull request tasks.
reqURL := setting.LocalURL + "api/internal/ssh/authorized_keys"
req := newInternalRequest(ctx, reqURL, "POST")
req.Param("content", content)
- resp, err := req.Response()
- if err != nil {
- return "", err
- }
-
- defer resp.Body.Close()
-
- // All 2XX status codes are accepted and others will return an error
- if resp.StatusCode != http.StatusOK {
- return "", fmt.Errorf("Failed to update public key: %s", decodeJSONError(resp).Err)
- }
- bs, err := io.ReadAll(resp.Body)
-
- return string(bs), err
+ resp, extra := requestJSONResp(req, &responseText{})
+ return resp.Text, extra
}
diff --git a/modules/private/mail.go b/modules/private/mail.go
index 6eb7c2acd0..82216b346b 100644
--- a/modules/private/mail.go
+++ b/modules/private/mail.go
@@ -5,11 +5,7 @@ package private
import (
"context"
- "fmt"
- "io"
- "net/http"
- "code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/setting"
)
@@ -21,38 +17,18 @@ type Email struct {
}
// SendEmail calls the internal SendEmail function
-//
// It accepts a list of usernames.
// If DB contains these users it will send the email to them.
-//
-// If to list == nil its supposed to send an email to every
-// user present in DB
-func SendEmail(ctx context.Context, subject, message string, to []string) (int, string) {
+// If to list == nil, it's supposed to send emails to every user present in DB
+func SendEmail(ctx context.Context, subject, message string, to []string) (string, ResponseExtra) {
reqURL := setting.LocalURL + "api/internal/mail/send"
- req := newInternalRequest(ctx, reqURL, "POST")
- req = req.Header("Content-Type", "application/json")
- jsonBytes, _ := json.Marshal(Email{
+ req := newInternalRequest(ctx, reqURL, "POST", Email{
Subject: subject,
Message: message,
To: to,
})
- req.Body(jsonBytes)
- resp, err := req.Response()
- if err != nil {
- return http.StatusInternalServerError, fmt.Sprintf("Unable to contact gitea: %v", err.Error())
- }
- defer resp.Body.Close()
- body, err := io.ReadAll(resp.Body)
- if err != nil {
- return http.StatusInternalServerError, fmt.Sprintf("Response body error: %v", err.Error())
- }
-
- users := fmt.Sprintf("%d", len(to))
- if len(to) == 0 {
- users = "all"
- }
-
- return http.StatusOK, fmt.Sprintf("Sent %s email(s) to %s users", body, users)
+ resp, extra := requestJSONResp(req, &responseText{})
+ return resp.Text, extra
}
diff --git a/modules/private/manager.go b/modules/private/manager.go
index bbf470cd7a..5853db34e4 100644
--- a/modules/private/manager.go
+++ b/modules/private/manager.go
@@ -12,44 +12,21 @@ import (
"strconv"
"time"
- "code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/setting"
)
// Shutdown calls the internal shutdown function
-func Shutdown(ctx context.Context) (int, string) {
+func Shutdown(ctx context.Context) ResponseExtra {
reqURL := setting.LocalURL + "api/internal/manager/shutdown"
-
req := newInternalRequest(ctx, reqURL, "POST")
- resp, err := req.Response()
- if err != nil {
- return http.StatusInternalServerError, fmt.Sprintf("Unable to contact gitea: %v", err.Error())
- }
- defer resp.Body.Close()
-
- if resp.StatusCode != http.StatusOK {
- return resp.StatusCode, decodeJSONError(resp).Err
- }
-
- return http.StatusOK, "Shutting down"
+ return requestJSONUserMsg(req, "Shutting down")
}
// Restart calls the internal restart function
-func Restart(ctx context.Context) (int, string) {
+func Restart(ctx context.Context) ResponseExtra {
reqURL := setting.LocalURL + "api/internal/manager/restart"
-
req := newInternalRequest(ctx, reqURL, "POST")
- resp, err := req.Response()
- if err != nil {
- return http.StatusInternalServerError, fmt.Sprintf("Unable to contact gitea: %v", err.Error())
- }
- defer resp.Body.Close()
-
- if resp.StatusCode != http.StatusOK {
- return resp.StatusCode, decodeJSONError(resp).Err
- }
-
- return http.StatusOK, "Restarting"
+ return requestJSONUserMsg(req, "Restarting")
}
// FlushOptions represents the options for the flush call
@@ -59,102 +36,41 @@ type FlushOptions struct {
}
// FlushQueues calls the internal flush-queues function
-func FlushQueues(ctx context.Context, timeout time.Duration, nonBlocking bool) (int, string) {
+func FlushQueues(ctx context.Context, timeout time.Duration, nonBlocking bool) ResponseExtra {
reqURL := setting.LocalURL + "api/internal/manager/flush-queues"
-
- req := newInternalRequest(ctx, reqURL, "POST")
+ req := newInternalRequest(ctx, reqURL, "POST", FlushOptions{Timeout: timeout, NonBlocking: nonBlocking})
if timeout > 0 {
- req.SetTimeout(timeout+10*time.Second, timeout+10*time.Second)
- }
- req = req.Header("Content-Type", "application/json")
- jsonBytes, _ := json.Marshal(FlushOptions{
- Timeout: timeout,
- NonBlocking: nonBlocking,
- })
- req.Body(jsonBytes)
- resp, err := req.Response()
- if err != nil {
- return http.StatusInternalServerError, fmt.Sprintf("Unable to contact gitea: %v", err.Error())
- }
- defer resp.Body.Close()
-
- if resp.StatusCode != http.StatusOK {
- return resp.StatusCode, decodeJSONError(resp).Err
+ req.SetReadWriteTimeout(timeout + 10*time.Second)
}
-
- return http.StatusOK, "Flushed"
+ return requestJSONUserMsg(req, "Flushed")
}
// PauseLogging pauses logging
-func PauseLogging(ctx context.Context) (int, string) {
+func PauseLogging(ctx context.Context) ResponseExtra {
reqURL := setting.LocalURL + "api/internal/manager/pause-logging"
-
req := newInternalRequest(ctx, reqURL, "POST")
- resp, err := req.Response()
- if err != nil {
- return http.StatusInternalServerError, fmt.Sprintf("Unable to contact gitea: %v", err.Error())
- }
- defer resp.Body.Close()
-
- if resp.StatusCode != http.StatusOK {
- return resp.StatusCode, decodeJSONError(resp).Err
- }
-
- return http.StatusOK, "Logging Paused"
+ return requestJSONUserMsg(req, "Logging Paused")
}
// ResumeLogging resumes logging
-func ResumeLogging(ctx context.Context) (int, string) {
+func ResumeLogging(ctx context.Context) ResponseExtra {
reqURL := setting.LocalURL + "api/internal/manager/resume-logging"
-
req := newInternalRequest(ctx, reqURL, "POST")
- resp, err := req.Response()
- if err != nil {
- return http.StatusInternalServerError, fmt.Sprintf("Unable to contact gitea: %v", err.Error())
- }
- defer resp.Body.Close()
-
- if resp.StatusCode != http.StatusOK {
- return resp.StatusCode, decodeJSONError(resp).Err
- }
-
- return http.StatusOK, "Logging Restarted"
+ return requestJSONUserMsg(req, "Logging Restarted")
}
// ReleaseReopenLogging releases and reopens logging files
-func ReleaseReopenLogging(ctx context.Context) (int, string) {
+func ReleaseReopenLogging(ctx context.Context) ResponseExtra {
reqURL := setting.LocalURL + "api/internal/manager/release-and-reopen-logging"
-
req := newInternalRequest(ctx, reqURL, "POST")
- resp, err := req.Response()
- if err != nil {
- return http.StatusInternalServerError, fmt.Sprintf("Unable to contact gitea: %v", err.Error())
- }
- defer resp.Body.Close()
-
- if resp.StatusCode != http.StatusOK {
- return resp.StatusCode, decodeJSONError(resp).Err
- }
-
- return http.StatusOK, "Logging Restarted"
+ return requestJSONUserMsg(req, "Logging Restarted")
}
// SetLogSQL sets database logging
-func SetLogSQL(ctx context.Context, on bool) (int, string) {
+func SetLogSQL(ctx context.Context, on bool) ResponseExtra {
reqURL := setting.LocalURL + "api/internal/manager/set-log-sql?on=" + strconv.FormatBool(on)
-
req := newInternalRequest(ctx, reqURL, "POST")
- resp, err := req.Response()
- if err != nil {
- return http.StatusInternalServerError, fmt.Sprintf("Unable to contact gitea: %v", err.Error())
- }
- defer resp.Body.Close()
-
- if resp.StatusCode != http.StatusOK {
- return resp.StatusCode, decodeJSONError(resp).Err
- }
-
- return http.StatusOK, "Log SQL setting set"
+ return requestJSONUserMsg(req, "Log SQL setting set")
}
// LoggerOptions represents the options for the add logger call
@@ -166,67 +82,32 @@ type LoggerOptions struct {
}
// AddLogger adds a logger
-func AddLogger(ctx context.Context, group, name, mode string, config map[string]interface{}) (int, string) {
+func AddLogger(ctx context.Context, group, name, mode string, config map[string]interface{}) ResponseExtra {
reqURL := setting.LocalURL + "api/internal/manager/add-logger"
-
- req := newInternalRequest(ctx, reqURL, "POST")
- req = req.Header("Content-Type", "application/json")
- jsonBytes, _ := json.Marshal(LoggerOptions{
+ req := newInternalRequest(ctx, reqURL, "POST", LoggerOptions{
Group: group,
Name: name,
Mode: mode,
Config: config,
})
- req.Body(jsonBytes)
- resp, err := req.Response()
- if err != nil {
- return http.StatusInternalServerError, fmt.Sprintf("Unable to contact gitea: %v", err.Error())
- }
- defer resp.Body.Close()
-
- if resp.StatusCode != http.StatusOK {
- return resp.StatusCode, decodeJSONError(resp).Err
- }
-
- return http.StatusOK, "Added"
+ return requestJSONUserMsg(req, "Added")
}
// RemoveLogger removes a logger
-func RemoveLogger(ctx context.Context, group, name string) (int, string) {
+func RemoveLogger(ctx context.Context, group, name string) ResponseExtra {
reqURL := setting.LocalURL + fmt.Sprintf("api/internal/manager/remove-logger/%s/%s", url.PathEscape(group), url.PathEscape(name))
-
req := newInternalRequest(ctx, reqURL, "POST")
- resp, err := req.Response()
- if err != nil {
- return http.StatusInternalServerError, fmt.Sprintf("Unable to contact gitea: %v", err.Error())
- }
- defer resp.Body.Close()
-
- if resp.StatusCode != http.StatusOK {
- return resp.StatusCode, decodeJSONError(resp).Err
- }
-
- return http.StatusOK, "Removed"
+ return requestJSONUserMsg(req, "Removed")
}
// Processes return the current processes from this gitea instance
-func Processes(ctx context.Context, out io.Writer, flat, noSystem, stacktraces, json bool, cancel string) (int, string) {
+func Processes(ctx context.Context, out io.Writer, flat, noSystem, stacktraces, json bool, cancel string) ResponseExtra {
reqURL := setting.LocalURL + fmt.Sprintf("api/internal/manager/processes?flat=%t&no-system=%t&stacktraces=%t&json=%t&cancel-pid=%s", flat, noSystem, stacktraces, json, url.QueryEscape(cancel))
req := newInternalRequest(ctx, reqURL, "GET")
- resp, err := req.Response()
- if err != nil {
- return http.StatusInternalServerError, fmt.Sprintf("Unable to contact gitea: %v", err.Error())
- }
- defer resp.Body.Close()
-
- if resp.StatusCode != http.StatusOK {
- return resp.StatusCode, decodeJSONError(resp).Err
- }
-
- _, err = io.Copy(out, resp.Body)
- if err != nil {
- return http.StatusInternalServerError, err.Error()
+ callback := func(resp *http.Response, extra *ResponseExtra) {
+ _, extra.Error = io.Copy(out, resp.Body)
}
- return http.StatusOK, ""
+ _, extra := requestJSONResp(req, &callback)
+ return extra
}
diff --git a/modules/private/request.go b/modules/private/request.go
new file mode 100644
index 0000000000..3eb8c92c1a
--- /dev/null
+++ b/modules/private/request.go
@@ -0,0 +1,135 @@
+// Copyright 2023 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package private
+
+import (
+ "fmt"
+ "io"
+ "net/http"
+ "unicode"
+
+ "code.gitea.io/gitea/modules/httplib"
+ "code.gitea.io/gitea/modules/json"
+)
+
+// responseText is used to get the response as text, instead of parsing it as JSON.
+type responseText struct {
+ Text string
+}
+
+// ResponseExtra contains extra information about the response, especially for error responses.
+type ResponseExtra struct {
+ StatusCode int
+ UserMsg string
+ Error error
+}
+
+type responseCallback func(resp *http.Response, extra *ResponseExtra)
+
+func (re *ResponseExtra) HasError() bool {
+ return re.Error != nil
+}
+
+type responseError struct {
+ statusCode int
+ errorString string
+}
+
+func (re responseError) Error() string {
+ if re.errorString == "" {
+ return fmt.Sprintf("internal API error response, status=%d", re.statusCode)
+ }
+ return fmt.Sprintf("internal API error response, status=%d, err=%s", re.statusCode, re.errorString)
+}
+
+// requestJSONUserMsg sends a request to the gitea server and then parses the response.
+// If the status code is not 2xx, or any error occurs, the ResponseExtra.Error field is guaranteed to be non-nil,
+// and the ResponseExtra.UserMsg field will be set to a message for the end user.
+//
+// * If the "res" is a struct pointer, the response will be parsed as JSON
+// * If the "res" is responseText pointer, the response will be stored as text in it
+// * If the "res" is responseCallback pointer, the callback function should set the ResponseExtra fields accordingly
+func requestJSONResp[T any](req *httplib.Request, res *T) (ret *T, extra ResponseExtra) {
+ resp, err := req.Response()
+ if err != nil {
+ extra.UserMsg = "Internal Server Connection Error"
+ extra.Error = fmt.Errorf("unable to contact gitea %q: %w", req.GoString(), err)
+ return nil, extra
+ }
+ defer resp.Body.Close()
+
+ extra.StatusCode = resp.StatusCode
+
+ // if the status code is not 2xx, try to parse the error response
+ if resp.StatusCode/100 != 2 {
+ var respErr Response
+ if err := json.NewDecoder(resp.Body).Decode(&respErr); err != nil {
+ extra.UserMsg = "Internal Server Error Decoding Failed"
+ extra.Error = fmt.Errorf("unable to decode error response %q: %w", req.GoString(), err)
+ return nil, extra
+ }
+ extra.UserMsg = respErr.UserMsg
+ if extra.UserMsg == "" {
+ extra.UserMsg = "Internal Server Error (no message for end users)"
+ }
+ extra.Error = responseError{statusCode: resp.StatusCode, errorString: respErr.Err}
+ return res, extra
+ }
+
+ // now, the StatusCode must be 2xx
+ var v any = res
+ if respText, ok := v.(*responseText); ok {
+ // get the whole response as a text string
+ bs, err := io.ReadAll(resp.Body)
+ if err != nil {
+ extra.UserMsg = "Internal Server Response Reading Failed"
+ extra.Error = fmt.Errorf("unable to read response %q: %w", req.GoString(), err)
+ return nil, extra
+ }
+ respText.Text = string(bs)
+ return res, extra
+ } else if callback, ok := v.(*responseCallback); ok {
+ // pass the response to callback, and let the callback update the ResponseExtra
+ extra.StatusCode = resp.StatusCode
+ (*callback)(resp, &extra)
+ return nil, extra
+ } else if err := json.NewDecoder(resp.Body).Decode(res); err != nil {
+ // decode the response into the given struct
+ extra.UserMsg = "Internal Server Response Decoding Failed"
+ extra.Error = fmt.Errorf("unable to decode response %q: %w", req.GoString(), err)
+ return nil, extra
+ }
+
+ if respMsg, ok := v.(*Response); ok {
+ // if the "res" is Response structure, try to get the UserMsg from it and update the ResponseExtra
+ extra.UserMsg = respMsg.UserMsg
+ if respMsg.Err != "" {
+ // usually this shouldn't happen, because the StatusCode is 2xx, there should be no error.
+ // but we still handle the "err" response, in case some people return error messages by status code 200.
+ extra.Error = responseError{statusCode: resp.StatusCode, errorString: respMsg.Err}
+ }
+ }
+
+ return res, extra
+}
+
+// requestJSONUserMsg sends a request to the gitea server and then parses the response as private.Response
+// If the request succeeds, the successMsg will be used as part of ResponseExtra.UserMsg.
+func requestJSONUserMsg(req *httplib.Request, successMsg string) ResponseExtra {
+ resp, extra := requestJSONResp(req, &Response{})
+ if extra.HasError() {
+ return extra
+ }
+ if resp.UserMsg == "" {
+ extra.UserMsg = successMsg // if UserMsg is empty, then use successMsg as userMsg
+ } else if successMsg != "" {
+ // else, now UserMsg is not empty, if successMsg is not empty, then append successMsg to UserMsg
+ if unicode.IsPunct(rune(extra.UserMsg[len(extra.UserMsg)-1])) {
+ extra.UserMsg = extra.UserMsg + " " + successMsg
+ } else {
+ extra.UserMsg = extra.UserMsg + ". " + successMsg
+ }
+ }
+ return extra
+}
diff --git a/modules/private/restore_repo.go b/modules/private/restore_repo.go
index f40d914a7b..34d0f5d482 100644
--- a/modules/private/restore_repo.go
+++ b/modules/private/restore_repo.go
@@ -6,11 +6,8 @@ package private
import (
"context"
"fmt"
- "io"
- "net/http"
"time"
- "code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/setting"
)
@@ -24,39 +21,16 @@ type RestoreParams struct {
}
// RestoreRepo calls the internal RestoreRepo function
-func RestoreRepo(ctx context.Context, repoDir, ownerName, repoName string, units []string, validation bool) (int, string) {
+func RestoreRepo(ctx context.Context, repoDir, ownerName, repoName string, units []string, validation bool) ResponseExtra {
reqURL := setting.LocalURL + "api/internal/restore_repo"
- req := newInternalRequest(ctx, reqURL, "POST")
- req.SetTimeout(3*time.Second, 0) // since the request will spend much time, don't timeout
- req = req.Header("Content-Type", "application/json")
- jsonBytes, _ := json.Marshal(RestoreParams{
+ req := newInternalRequest(ctx, reqURL, "POST", RestoreParams{
RepoDir: repoDir,
OwnerName: ownerName,
RepoName: repoName,
Units: units,
Validation: validation,
})
- req.Body(jsonBytes)
- resp, err := req.Response()
- if err != nil {
- return http.StatusInternalServerError, fmt.Sprintf("Unable to contact gitea: %v, could you confirm it's running?", err.Error())
- }
- defer resp.Body.Close()
-
- if resp.StatusCode != http.StatusOK {
- ret := struct {
- Err string `json:"err"`
- }{}
- body, err := io.ReadAll(resp.Body)
- if err != nil {
- return http.StatusInternalServerError, fmt.Sprintf("Response body error: %v", err.Error())
- }
- if err := json.Unmarshal(body, &ret); err != nil {
- return http.StatusInternalServerError, fmt.Sprintf("Response body Unmarshal error: %v", err.Error())
- }
- return http.StatusInternalServerError, ret.Err
- }
-
- return http.StatusOK, fmt.Sprintf("Restore repo %s/%s successfully", ownerName, repoName)
+ req.SetTimeout(3*time.Second, 0) // since the request will spend much time, don't timeout
+ return requestJSONUserMsg(req, fmt.Sprintf("Restore repo %s/%s successfully", ownerName, repoName))
}
diff --git a/modules/private/serv.go b/modules/private/serv.go
index c176e1ddfc..480a446954 100644
--- a/modules/private/serv.go
+++ b/modules/private/serv.go
@@ -6,13 +6,11 @@ package private
import (
"context"
"fmt"
- "net/http"
"net/url"
asymkey_model "code.gitea.io/gitea/models/asymkey"
"code.gitea.io/gitea/models/perm"
user_model "code.gitea.io/gitea/models/user"
- "code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/setting"
)
@@ -24,20 +22,11 @@ type KeyAndOwner struct {
// ServNoCommand returns information about the provided key
func ServNoCommand(ctx context.Context, keyID int64) (*asymkey_model.PublicKey, *user_model.User, error) {
- reqURL := setting.LocalURL + fmt.Sprintf("api/internal/serv/none/%d",
- keyID)
- resp, err := newInternalRequest(ctx, reqURL, "GET").Response()
- if err != nil {
- return nil, nil, err
- }
- defer resp.Body.Close()
- if resp.StatusCode != http.StatusOK {
- return nil, nil, fmt.Errorf("%s", decodeJSONError(resp).Err)
- }
-
- var keyAndOwner KeyAndOwner
- if err := json.NewDecoder(resp.Body).Decode(&keyAndOwner); err != nil {
- return nil, nil, err
+ reqURL := setting.LocalURL + fmt.Sprintf("api/internal/serv/none/%d", keyID)
+ req := newInternalRequest(ctx, reqURL, "GET")
+ keyAndOwner, extra := requestJSONResp(req, &KeyAndOwner{})
+ if extra.HasError() {
+ return nil, nil, extra.Error
}
return keyAndOwner.Key, keyAndOwner.Owner, nil
}
@@ -56,53 +45,19 @@ type ServCommandResults struct {
RepoID int64
}
-// ErrServCommand is an error returned from ServCommmand.
-type ErrServCommand struct {
- Results ServCommandResults
- Err string
- StatusCode int
-}
-
-func (err ErrServCommand) Error() string {
- return err.Err
-}
-
-// IsErrServCommand checks if an error is a ErrServCommand.
-func IsErrServCommand(err error) bool {
- _, ok := err.(ErrServCommand)
- return ok
-}
-
// ServCommand preps for a serv call
-func ServCommand(ctx context.Context, keyID int64, ownerName, repoName string, mode perm.AccessMode, verbs ...string) (*ServCommandResults, error) {
+func ServCommand(ctx context.Context, keyID int64, ownerName, repoName string, mode perm.AccessMode, verbs ...string) (*ServCommandResults, ResponseExtra) {
reqURL := setting.LocalURL + fmt.Sprintf("api/internal/serv/command/%d/%s/%s?mode=%d",
keyID,
url.PathEscape(ownerName),
url.PathEscape(repoName),
- mode)
+ mode,
+ )
for _, verb := range verbs {
if verb != "" {
reqURL += fmt.Sprintf("&verb=%s", url.QueryEscape(verb))
}
}
-
- resp, err := newInternalRequest(ctx, reqURL, "GET").Response()
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- if resp.StatusCode != http.StatusOK {
- var errServCommand ErrServCommand
- if err := json.NewDecoder(resp.Body).Decode(&errServCommand); err != nil {
- return nil, err
- }
- errServCommand.StatusCode = resp.StatusCode
- return nil, errServCommand
- }
- var results ServCommandResults
- if err := json.NewDecoder(resp.Body).Decode(&results); err != nil {
- return nil, err
- }
- return &results, nil
+ req := newInternalRequest(ctx, reqURL, "GET")
+ return requestJSONResp(req, &ServCommandResults{})
}
diff --git a/routers/private/default_branch.go b/routers/private/default_branch.go
index 268ebbe443..b15d6ba33a 100644
--- a/routers/private/default_branch.go
+++ b/routers/private/default_branch.go
@@ -1,7 +1,6 @@
// Copyright 2021 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
-// Package private includes all internal routes. The package name internal is ideal but Golang is not allowed, so we use private as package name instead.
package private
import (
@@ -14,19 +13,6 @@ import (
"code.gitea.io/gitea/modules/private"
)
-// ________ _____ .__ __
-// \______ \ _____/ ____\____ __ __| |_/ |_
-// | | \_/ __ \ __\\__ \ | | \ |\ __\
-// | ` \ ___/| | / __ \| | / |_| |
-// /_______ /\___ >__| (____ /____/|____/__|
-// \/ \/ \/
-// __________ .__
-// \______ \____________ ____ ____ | |__
-// | | _/\_ __ \__ \ / \_/ ___\| | \
-// | | \ | | \// __ \| | \ \___| Y \
-// |______ / |__| (____ /___| /\___ >___| /
-// \/ \/ \/ \/ \/
-
// SetDefaultBranch updates the default branch
func SetDefaultBranch(ctx *gitea_context.PrivateContext) {
ownerName := ctx.Params(":owner")
diff --git a/routers/private/hook_post_receive.go b/routers/private/hook_post_receive.go
index 75de47bdc4..cfe20be106 100644
--- a/routers/private/hook_post_receive.go
+++ b/routers/private/hook_post_receive.go
@@ -1,7 +1,6 @@
// Copyright 2021 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
-// Package private includes all internal routes. The package name internal is ideal but Golang is not allowed, so we use private as package name instead.
package private
import (
diff --git a/routers/private/hook_pre_receive.go b/routers/private/hook_pre_receive.go
index c711fc9477..63b4a8622e 100644
--- a/routers/private/hook_pre_receive.go
+++ b/routers/private/hook_pre_receive.go
@@ -1,7 +1,6 @@
// Copyright 2019 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
-// Package private includes all internal routes. The package name internal is ideal but Golang is not allowed, so we use private as package name instead.
package private
import (
@@ -69,8 +68,8 @@ func (ctx *preReceiveContext) AssertCanWriteCode() bool {
if ctx.Written() {
return false
}
- ctx.JSON(http.StatusForbidden, map[string]interface{}{
- "err": "User permission denied for writing.",
+ ctx.JSON(http.StatusForbidden, private.Response{
+ UserMsg: "User permission denied for writing.",
})
return false
}
@@ -95,8 +94,8 @@ func (ctx *preReceiveContext) AssertCreatePullRequest() bool {
if ctx.Written() {
return false
}
- ctx.JSON(http.StatusForbidden, map[string]interface{}{
- "err": "User permission denied for creating pull-request.",
+ ctx.JSON(http.StatusForbidden, private.Response{
+ UserMsg: "User permission denied for creating pull-request.",
})
return false
}
@@ -151,7 +150,7 @@ func preReceiveBranch(ctx *preReceiveContext, oldCommitID, newCommitID, refFullN
if branchName == repo.DefaultBranch && newCommitID == git.EmptySHA {
log.Warn("Forbidden: Branch: %s is the default branch in %-v and cannot be deleted", branchName, repo)
ctx.JSON(http.StatusForbidden, private.Response{
- Err: fmt.Sprintf("branch %s is the default branch and cannot be deleted", branchName),
+ UserMsg: fmt.Sprintf("branch %s is the default branch and cannot be deleted", branchName),
})
return
}
@@ -179,7 +178,7 @@ func preReceiveBranch(ctx *preReceiveContext, oldCommitID, newCommitID, refFullN
if newCommitID == git.EmptySHA {
log.Warn("Forbidden: Branch: %s in %-v is protected from deletion", branchName, repo)
ctx.JSON(http.StatusForbidden, private.Response{
- Err: fmt.Sprintf("branch %s is protected from deletion", branchName),
+ UserMsg: fmt.Sprintf("branch %s is protected from deletion", branchName),
})
return
}
@@ -196,7 +195,7 @@ func preReceiveBranch(ctx *preReceiveContext, oldCommitID, newCommitID, refFullN
} else if len(output) > 0 {
log.Warn("Forbidden: Branch: %s in %-v is protected from force push", branchName, repo)
ctx.JSON(http.StatusForbidden, private.Response{
- Err: fmt.Sprintf("branch %s is protected from force push", branchName),
+ UserMsg: fmt.Sprintf("branch %s is protected from force push", branchName),
})
return
@@ -217,7 +216,7 @@ func preReceiveBranch(ctx *preReceiveContext, oldCommitID, newCommitID, refFullN
unverifiedCommit := err.(*errUnverifiedCommit).sha
log.Warn("Forbidden: Branch: %s in %-v is protected from unverified commit %s", branchName, repo, unverifiedCommit)
ctx.JSON(http.StatusForbidden, private.Response{
- Err: fmt.Sprintf("branch %s is protected from unverified commit %s", branchName, unverifiedCommit),
+ UserMsg: fmt.Sprintf("branch %s is protected from unverified commit %s", branchName, unverifiedCommit),
})
return
}
@@ -272,7 +271,7 @@ func preReceiveBranch(ctx *preReceiveContext, oldCommitID, newCommitID, refFullN
if changedProtectedfiles {
log.Warn("Forbidden: Branch: %s in %-v is protected from changing file %s", branchName, repo, protectedFilePath)
ctx.JSON(http.StatusForbidden, private.Response{
- Err: fmt.Sprintf("branch %s is protected from changing file %s", branchName, protectedFilePath),
+ UserMsg: fmt.Sprintf("branch %s is protected from changing file %s", branchName, protectedFilePath),
})
return
}
@@ -297,7 +296,7 @@ func preReceiveBranch(ctx *preReceiveContext, oldCommitID, newCommitID, refFullN
// Or we're simply not able to push to this protected branch
log.Warn("Forbidden: User %d is not allowed to push to protected branch: %s in %-v", ctx.opts.UserID, branchName, repo)
ctx.JSON(http.StatusForbidden, private.Response{
- Err: fmt.Sprintf("Not allowed to push to protected branch %s", branchName),
+ UserMsg: fmt.Sprintf("Not allowed to push to protected branch %s", branchName),
})
return
}
@@ -333,7 +332,7 @@ func preReceiveBranch(ctx *preReceiveContext, oldCommitID, newCommitID, refFullN
if !allowedMerge {
log.Warn("Forbidden: User %d is not allowed to push to protected branch: %s in %-v and is not allowed to merge pr #%d", ctx.opts.UserID, branchName, repo, pr.Index)
ctx.JSON(http.StatusForbidden, private.Response{
- Err: fmt.Sprintf("Not allowed to push to protected branch %s", branchName),
+ UserMsg: fmt.Sprintf("Not allowed to push to protected branch %s", branchName),
})
return
}
@@ -347,7 +346,7 @@ func preReceiveBranch(ctx *preReceiveContext, oldCommitID, newCommitID, refFullN
if changedProtectedfiles {
log.Warn("Forbidden: Branch: %s in %-v is protected from changing file %s", branchName, repo, protectedFilePath)
ctx.JSON(http.StatusForbidden, private.Response{
- Err: fmt.Sprintf("branch %s is protected from changing file %s", branchName, protectedFilePath),
+ UserMsg: fmt.Sprintf("branch %s is protected from changing file %s", branchName, protectedFilePath),
})
return
}
@@ -357,7 +356,7 @@ func preReceiveBranch(ctx *preReceiveContext, oldCommitID, newCommitID, refFullN
if models.IsErrDisallowedToMerge(err) {
log.Warn("Forbidden: User %d is not allowed push to protected branch %s in %-v and pr #%d is not ready to be merged: %s", ctx.opts.UserID, branchName, repo, pr.Index, err.Error())
ctx.JSON(http.StatusForbidden, private.Response{
- Err: fmt.Sprintf("Not allowed to push to protected branch %s and pr #%d is not ready to be merged: %s", branchName, ctx.opts.PullRequestID, err.Error()),
+ UserMsg: fmt.Sprintf("Not allowed to push to protected branch %s and pr #%d is not ready to be merged: %s", branchName, ctx.opts.PullRequestID, err.Error()),
})
return
}
@@ -400,7 +399,7 @@ func preReceiveTag(ctx *preReceiveContext, oldCommitID, newCommitID, refFullName
if !isAllowed {
log.Warn("Forbidden: Tag %s in %-v is protected", tagName, ctx.Repo.Repository)
ctx.JSON(http.StatusForbidden, private.Response{
- Err: fmt.Sprintf("Tag %s is protected", tagName),
+ UserMsg: fmt.Sprintf("Tag %s is protected", tagName),
})
return
}
@@ -412,15 +411,15 @@ func preReceivePullRequest(ctx *preReceiveContext, oldCommitID, newCommitID, ref
}
if ctx.Repo.Repository.IsEmpty {
- ctx.JSON(http.StatusForbidden, map[string]interface{}{
- "err": "Can't create pull request for an empty repository.",
+ ctx.JSON(http.StatusForbidden, private.Response{
+ UserMsg: "Can't create pull request for an empty repository.",
})
return
}
if ctx.opts.IsWiki {
- ctx.JSON(http.StatusForbidden, map[string]interface{}{
- "err": "Pull requests are not supported on the wiki.",
+ ctx.JSON(http.StatusForbidden, private.Response{
+ UserMsg: "Pull requests are not supported on the wiki.",
})
return
}
@@ -443,7 +442,7 @@ func preReceivePullRequest(ctx *preReceiveContext, oldCommitID, newCommitID, ref
if !baseBranchExist {
ctx.JSON(http.StatusForbidden, private.Response{
- Err: fmt.Sprintf("Unexpected ref: %s", refFullName),
+ UserMsg: fmt.Sprintf("Unexpected ref: %s", refFullName),
})
return
}
diff --git a/routers/private/hook_proc_receive.go b/routers/private/hook_proc_receive.go
index 05921e6f58..5577120770 100644
--- a/routers/private/hook_proc_receive.go
+++ b/routers/private/hook_proc_receive.go
@@ -1,7 +1,6 @@
// Copyright 2021 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
-// Package private includes all internal routes. The package name internal is ideal but Golang is not allowed, so we use private as package name instead.
package private
import (
@@ -30,8 +29,8 @@ func HookProcReceive(ctx *gitea_context.PrivateContext) {
ctx.Error(http.StatusBadRequest, "UserDoesNotHaveAccessToRepo", err.Error())
} else {
log.Error(err.Error())
- ctx.JSON(http.StatusInternalServerError, map[string]interface{}{
- "Err": err.Error(),
+ ctx.JSON(http.StatusInternalServerError, private.Response{
+ Err: err.Error(),
})
}
diff --git a/routers/private/hook_verification.go b/routers/private/hook_verification.go
index 8ccde4f3d7..caf3874ec3 100644
--- a/routers/private/hook_verification.go
+++ b/routers/private/hook_verification.go
@@ -1,7 +1,6 @@
// Copyright 2021 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
-// Package private includes all internal routes. The package name internal is ideal but Golang is not allowed, so we use private as package name instead.
package private
import (
@@ -16,19 +15,6 @@ import (
"code.gitea.io/gitea/modules/log"
)
-// _________ .__ __
-// \_ ___ \ ____ _____ _____ |__|/ |_
-// / \ \/ / _ \ / \ / \| \ __\
-// \ \___( <_> ) Y Y \ Y Y \ || |
-// \______ /\____/|__|_| /__|_| /__||__|
-// \/ \/ \/
-// ____ ____ .__ _____.__ __ .__
-// \ \ / /___________|__|/ ____\__| ____ _____ _/ |_|__| ____ ____
-// \ Y // __ \_ __ \ \ __\| |/ ___\\__ \\ __\ |/ _ \ / \
-// \ /\ ___/| | \/ || | | \ \___ / __ \| | | ( <_> ) | \
-// \___/ \___ >__| |__||__| |__|\___ >____ /__| |__|\____/|___| /
-// \/ \/ \/ \/
-//
// This file contains commit verification functions for refs passed across in hooks
func verifyCommits(oldCommitID, newCommitID string, repo *git.Repository, env []string) error {
diff --git a/routers/private/internal.go b/routers/private/internal.go
index 306e4ffb00..4acede3370 100644
--- a/routers/private/internal.go
+++ b/routers/private/internal.go
@@ -1,7 +1,7 @@
// Copyright 2017 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
-// Package private includes all internal routes. The package name internal is ideal but Golang is not allowed, so we use private as package name instead.
+// Package private contains all internal routes. The package name "internal" isn't usable because Golang reserves it for disabling cross-package usage.
package private
import (
diff --git a/routers/private/internal_repo.go b/routers/private/internal_repo.go
index bd8db0a185..5e7e82b03c 100644
--- a/routers/private/internal_repo.go
+++ b/routers/private/internal_repo.go
@@ -1,7 +1,6 @@
// Copyright 2021 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
-// Package private includes all internal routes. The package name internal is ideal but Golang is not allowed, so we use private as package name instead.
package private
import (
@@ -13,23 +12,10 @@ import (
gitea_context "code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
+ "code.gitea.io/gitea/modules/private"
)
-// __________
-// \______ \ ____ ______ ____
-// | _// __ \\____ \ / _ \
-// | | \ ___/| |_> > <_> )
-// |____|_ /\___ > __/ \____/
-// \/ \/|__|
-// _____ .__ __
-// / _ \ ______ _____|__| ____ ____ _____ ____ _____/ |_
-// / /_\ \ / ___// ___/ |/ ___\ / \ / \_/ __ \ / \ __\
-// / | \\___ \ \___ \| / /_/ > | \ Y Y \ ___/| | \ |
-// \____|__ /____ >____ >__\___ /|___| /__|_| /\___ >___| /__|
-// \/ \/ \/ /_____/ \/ \/ \/ \/
-
-// This file contains common functions relating to setting the Repository for the
-// internal routes
+// This file contains common functions relating to setting the Repository for the internal routes
// RepoAssignment assigns the repository and gitrepository to the private context
func RepoAssignment(ctx *gitea_context.PrivateContext) context.CancelFunc {
@@ -45,8 +31,8 @@ func RepoAssignment(ctx *gitea_context.PrivateContext) context.CancelFunc {
gitRepo, err := git.OpenRepository(ctx, repo.RepoPath())
if err != nil {
log.Error("Failed to open repository: %s/%s Error: %v", ownerName, repoName, err)
- ctx.JSON(http.StatusInternalServerError, map[string]interface{}{
- "Err": fmt.Sprintf("Failed to open repository: %s/%s Error: %v", ownerName, repoName, err),
+ ctx.JSON(http.StatusInternalServerError, private.Response{
+ Err: fmt.Sprintf("Failed to open repository: %s/%s Error: %v", ownerName, repoName, err),
})
return nil
}
@@ -71,8 +57,8 @@ func loadRepository(ctx *gitea_context.PrivateContext, ownerName, repoName strin
repo, err := repo_model.GetRepositoryByOwnerAndName(ctx, ownerName, repoName)
if err != nil {
log.Error("Failed to get repository: %s/%s Error: %v", ownerName, repoName, err)
- ctx.JSON(http.StatusInternalServerError, map[string]interface{}{
- "Err": fmt.Sprintf("Failed to get repository: %s/%s Error: %v", ownerName, repoName, err),
+ ctx.JSON(http.StatusInternalServerError, private.Response{
+ Err: fmt.Sprintf("Failed to get repository: %s/%s Error: %v", ownerName, repoName, err),
})
return nil
}
diff --git a/routers/private/key.go b/routers/private/key.go
index b536019dd7..a13b4c12ae 100644
--- a/routers/private/key.go
+++ b/routers/private/key.go
@@ -1,7 +1,6 @@
// Copyright 2018 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
-// Package private includes all internal routes. The package name internal is ideal but Golang is not allowed, so we use private as package name instead.
package private
import (
diff --git a/routers/private/manager.go b/routers/private/manager.go
index a56fe9d123..38ad83326f 100644
--- a/routers/private/manager.go
+++ b/routers/private/manager.go
@@ -31,14 +31,14 @@ func FlushQueues(ctx *context.PrivateContext) {
}
}()
ctx.JSON(http.StatusAccepted, private.Response{
- Err: "Flushing",
+ UserMsg: "Flushing",
})
return
}
err := queue.GetManager().FlushAll(ctx, opts.Timeout)
if err != nil {
ctx.JSON(http.StatusRequestTimeout, private.Response{
- Err: fmt.Sprintf("%v", err),
+ UserMsg: fmt.Sprintf("%v", err),
})
}
ctx.PlainText(http.StatusOK, "success")
diff --git a/routers/private/manager_windows.go b/routers/private/manager_windows.go
index b5382c7d91..bd3c3c30d0 100644
--- a/routers/private/manager_windows.go
+++ b/routers/private/manager_windows.go
@@ -16,7 +16,7 @@ import (
// Restart is not implemented for Windows based servers as they can't fork
func Restart(ctx *context.PrivateContext) {
ctx.JSON(http.StatusNotImplemented, private.Response{
- Err: "windows servers cannot be gracefully restarted - shutdown and restart manually",
+ UserMsg: "windows servers cannot be gracefully restarted - shutdown and restart manually",
})
}
diff --git a/routers/private/serv.go b/routers/private/serv.go
index 23ac011cf5..b1efc58800 100644
--- a/routers/private/serv.go
+++ b/routers/private/serv.go
@@ -1,7 +1,6 @@
// Copyright 2019 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
-// Package private includes all internal routes. The package name internal is ideal but Golang is not allowed, so we use private as package name instead.
package private
import (
@@ -29,7 +28,7 @@ func ServNoCommand(ctx *context.PrivateContext) {
keyID := ctx.ParamsInt64(":keyid")
if keyID <= 0 {
ctx.JSON(http.StatusBadRequest, private.Response{
- Err: fmt.Sprintf("Bad key id: %d", keyID),
+ UserMsg: fmt.Sprintf("Bad key id: %d", keyID),
})
}
results := private.KeyAndOwner{}
@@ -38,7 +37,7 @@ func ServNoCommand(ctx *context.PrivateContext) {
if err != nil {
if asymkey_model.IsErrKeyNotExist(err) {
ctx.JSON(http.StatusUnauthorized, private.Response{
- Err: fmt.Sprintf("Cannot find key: %d", keyID),
+ UserMsg: fmt.Sprintf("Cannot find key: %d", keyID),
})
return
}
@@ -55,7 +54,7 @@ func ServNoCommand(ctx *context.PrivateContext) {
if err != nil {
if user_model.IsErrUserNotExist(err) {
ctx.JSON(http.StatusUnauthorized, private.Response{
- Err: fmt.Sprintf("Cannot find owner with id: %d for key: %d", key.OwnerID, keyID),
+ UserMsg: fmt.Sprintf("Cannot find owner with id: %d for key: %d", key.OwnerID, keyID),
})
return
}
@@ -67,7 +66,7 @@ func ServNoCommand(ctx *context.PrivateContext) {
}
if !user.IsActive || user.ProhibitLogin {
ctx.JSON(http.StatusForbidden, private.Response{
- Err: "Your account is disabled.",
+ UserMsg: "Your account is disabled.",
})
return
}
@@ -113,23 +112,20 @@ func ServCommand(ctx *context.PrivateContext) {
if user_model.IsErrUserNotExist(err) {
// User is fetching/cloning a non-existent repository
log.Warn("Failed authentication attempt (cannot find repository: %s/%s) from %s", results.OwnerName, results.RepoName, ctx.RemoteAddr())
- ctx.JSON(http.StatusNotFound, private.ErrServCommand{
- Results: results,
- Err: fmt.Sprintf("Cannot find repository: %s/%s", results.OwnerName, results.RepoName),
+ ctx.JSON(http.StatusNotFound, private.Response{
+ UserMsg: fmt.Sprintf("Cannot find repository: %s/%s", results.OwnerName, results.RepoName),
})
return
}
log.Error("Unable to get repository owner: %s/%s Error: %v", results.OwnerName, results.RepoName, err)
- ctx.JSON(http.StatusForbidden, private.ErrServCommand{
- Results: results,
- Err: fmt.Sprintf("Unable to get repository owner: %s/%s %v", results.OwnerName, results.RepoName, err),
+ ctx.JSON(http.StatusForbidden, private.Response{
+ UserMsg: fmt.Sprintf("Unable to get repository owner: %s/%s %v", results.OwnerName, results.RepoName, err),
})
return
}
if !owner.IsOrganization() && !owner.IsActive {
- ctx.JSON(http.StatusForbidden, private.ErrServCommand{
- Results: results,
- Err: "Repository cannot be accessed, you could retry it later",
+ ctx.JSON(http.StatusForbidden, private.Response{
+ UserMsg: "Repository cannot be accessed, you could retry it later",
})
return
}
@@ -144,18 +140,16 @@ func ServCommand(ctx *context.PrivateContext) {
if verb == "git-upload-pack" {
// User is fetching/cloning a non-existent repository
log.Warn("Failed authentication attempt (cannot find repository: %s/%s) from %s", results.OwnerName, results.RepoName, ctx.RemoteAddr())
- ctx.JSON(http.StatusNotFound, private.ErrServCommand{
- Results: results,
- Err: fmt.Sprintf("Cannot find repository: %s/%s", results.OwnerName, results.RepoName),
+ ctx.JSON(http.StatusNotFound, private.Response{
+ UserMsg: fmt.Sprintf("Cannot find repository: %s/%s", results.OwnerName, results.RepoName),
})
return
}
}
} else {
log.Error("Unable to get repository: %s/%s Error: %v", results.OwnerName, results.RepoName, err)
- ctx.JSON(http.StatusInternalServerError, private.ErrServCommand{
- Results: results,
- Err: fmt.Sprintf("Unable to get repository: %s/%s %v", results.OwnerName, results.RepoName, err),
+ ctx.JSON(http.StatusInternalServerError, private.Response{
+ Err: fmt.Sprintf("Unable to get repository: %s/%s %v", results.OwnerName, results.RepoName, err),
})
return
}
@@ -167,26 +161,23 @@ func ServCommand(ctx *context.PrivateContext) {
results.RepoID = repo.ID
if repo.IsBeingCreated() {
- ctx.JSON(http.StatusInternalServerError, private.ErrServCommand{
- Results: results,
- Err: "Repository is being created, you could retry after it finished",
+ ctx.JSON(http.StatusInternalServerError, private.Response{
+ Err: "Repository is being created, you could retry after it finished",
})
return
}
if repo.IsBroken() {
- ctx.JSON(http.StatusInternalServerError, private.ErrServCommand{
- Results: results,
- Err: "Repository is in a broken state",
+ ctx.JSON(http.StatusInternalServerError, private.Response{
+ Err: "Repository is in a broken state",
})
return
}
// We can shortcut at this point if the repo is a mirror
if mode > perm.AccessModeRead && repo.IsMirror {
- ctx.JSON(http.StatusForbidden, private.ErrServCommand{
- Results: results,
- Err: fmt.Sprintf("Mirror Repository %s/%s is read-only", results.OwnerName, results.RepoName),
+ ctx.JSON(http.StatusForbidden, private.Response{
+ UserMsg: fmt.Sprintf("Mirror Repository %s/%s is read-only", results.OwnerName, results.RepoName),
})
return
}
@@ -196,16 +187,14 @@ func ServCommand(ctx *context.PrivateContext) {
key, err := asymkey_model.GetPublicKeyByID(keyID)
if err != nil {
if asymkey_model.IsErrKeyNotExist(err) {
- ctx.JSON(http.StatusNotFound, private.ErrServCommand{
- Results: results,
- Err: fmt.Sprintf("Cannot find key: %d", keyID),
+ ctx.JSON(http.StatusNotFound, private.Response{
+ UserMsg: fmt.Sprintf("Cannot find key: %d", keyID),
})
return
}
log.Error("Unable to get public key: %d Error: %v", keyID, err)
- ctx.JSON(http.StatusInternalServerError, private.ErrServCommand{
- Results: results,
- Err: fmt.Sprintf("Unable to get key: %d Error: %v", keyID, err),
+ ctx.JSON(http.StatusInternalServerError, private.Response{
+ Err: fmt.Sprintf("Unable to get key: %d Error: %v", keyID, err),
})
return
}
@@ -215,9 +204,8 @@ func ServCommand(ctx *context.PrivateContext) {
// If repo doesn't exist, deploy key doesn't make sense
if !repoExist && key.Type == asymkey_model.KeyTypeDeploy {
- ctx.JSON(http.StatusNotFound, private.ErrServCommand{
- Results: results,
- Err: fmt.Sprintf("Cannot find repository %s/%s", results.OwnerName, results.RepoName),
+ ctx.JSON(http.StatusNotFound, private.Response{
+ UserMsg: fmt.Sprintf("Cannot find repository %s/%s", results.OwnerName, results.RepoName),
})
return
}
@@ -232,16 +220,14 @@ func ServCommand(ctx *context.PrivateContext) {
deployKey, err = asymkey_model.GetDeployKeyByRepo(ctx, key.ID, repo.ID)
if err != nil {
if asymkey_model.IsErrDeployKeyNotExist(err) {
- ctx.JSON(http.StatusNotFound, private.ErrServCommand{
- Results: results,
- Err: fmt.Sprintf("Public (Deploy) Key: %d:%s is not authorized to %s %s/%s.", key.ID, key.Name, modeString, results.OwnerName, results.RepoName),
+ ctx.JSON(http.StatusNotFound, private.Response{
+ UserMsg: fmt.Sprintf("Public (Deploy) Key: %d:%s is not authorized to %s %s/%s.", key.ID, key.Name, modeString, results.OwnerName, results.RepoName),
})
return
}
log.Error("Unable to get deploy for public (deploy) key: %d in %-v Error: %v", key.ID, repo, err)
- ctx.JSON(http.StatusInternalServerError, private.ErrServCommand{
- Results: results,
- Err: fmt.Sprintf("Unable to get Deploy Key for Public Key: %d:%s in %s/%s.", key.ID, key.Name, results.OwnerName, results.RepoName),
+ ctx.JSON(http.StatusInternalServerError, private.Response{
+ Err: fmt.Sprintf("Unable to get Deploy Key for Public Key: %d:%s in %s/%s.", key.ID, key.Name, results.OwnerName, results.RepoName),
})
return
}
@@ -262,23 +248,21 @@ func ServCommand(ctx *context.PrivateContext) {
user, err = user_model.GetUserByID(ctx, key.OwnerID)
if err != nil {
if user_model.IsErrUserNotExist(err) {
- ctx.JSON(http.StatusUnauthorized, private.ErrServCommand{
- Results: results,
- Err: fmt.Sprintf("Public Key: %d:%s owner %d does not exist.", key.ID, key.Name, key.OwnerID),
+ ctx.JSON(http.StatusUnauthorized, private.Response{
+ UserMsg: fmt.Sprintf("Public Key: %d:%s owner %d does not exist.", key.ID, key.Name, key.OwnerID),
})
return
}
log.Error("Unable to get owner: %d for public key: %d:%s Error: %v", key.OwnerID, key.ID, key.Name, err)
- ctx.JSON(http.StatusInternalServerError, private.ErrServCommand{
- Results: results,
- Err: fmt.Sprintf("Unable to get Owner: %d for Deploy Key: %d:%s in %s/%s.", key.OwnerID, key.ID, key.Name, ownerName, repoName),
+ ctx.JSON(http.StatusInternalServerError, private.Response{
+ Err: fmt.Sprintf("Unable to get Owner: %d for Deploy Key: %d:%s in %s/%s.", key.OwnerID, key.ID, key.Name, ownerName, repoName),
})
return
}
if !user.IsActive || user.ProhibitLogin {
ctx.JSON(http.StatusForbidden, private.Response{
- Err: "Your account is disabled.",
+ UserMsg: "Your account is disabled.",
})
return
}
@@ -291,9 +275,8 @@ func ServCommand(ctx *context.PrivateContext) {
// Don't allow pushing if the repo is archived
if repoExist && mode > perm.AccessModeRead && repo.IsArchived {
- ctx.JSON(http.StatusUnauthorized, private.ErrServCommand{
- Results: results,
- Err: fmt.Sprintf("Repo: %s/%s is archived.", results.OwnerName, results.RepoName),
+ ctx.JSON(http.StatusUnauthorized, private.Response{
+ UserMsg: fmt.Sprintf("Repo: %s/%s is archived.", results.OwnerName, results.RepoName),
})
return
}
@@ -307,9 +290,8 @@ func ServCommand(ctx *context.PrivateContext) {
setting.Service.RequireSignInView) {
if key.Type == asymkey_model.KeyTypeDeploy {
if deployKey.Mode < mode {
- ctx.JSON(http.StatusUnauthorized, private.ErrServCommand{
- Results: results,
- Err: fmt.Sprintf("Deploy Key: %d:%s is not authorized to %s %s/%s.", key.ID, key.Name, modeString, results.OwnerName, results.RepoName),
+ ctx.JSON(http.StatusUnauthorized, private.Response{
+ UserMsg: fmt.Sprintf("Deploy Key: %d:%s is not authorized to %s %s/%s.", key.ID, key.Name, modeString, results.OwnerName, results.RepoName),
})
return
}
@@ -322,9 +304,8 @@ func ServCommand(ctx *context.PrivateContext) {
perm, err := access_model.GetUserRepoPermission(ctx, repo, user)
if err != nil {
log.Error("Unable to get permissions for %-v with key %d in %-v Error: %v", user, key.ID, repo, err)
- ctx.JSON(http.StatusInternalServerError, private.ErrServCommand{
- Results: results,
- Err: fmt.Sprintf("Unable to get permissions for user %d:%s with key %d in %s/%s Error: %v", user.ID, user.Name, key.ID, results.OwnerName, results.RepoName, err),
+ ctx.JSON(http.StatusInternalServerError, private.Response{
+ Err: fmt.Sprintf("Unable to get permissions for user %d:%s with key %d in %s/%s Error: %v", user.ID, user.Name, key.ID, results.OwnerName, results.RepoName, err),
})
return
}
@@ -333,9 +314,8 @@ func ServCommand(ctx *context.PrivateContext) {
if userMode < mode {
log.Warn("Failed authentication attempt for %s with key %s (not authorized to %s %s/%s) from %s", user.Name, key.Name, modeString, ownerName, repoName, ctx.RemoteAddr())
- ctx.JSON(http.StatusUnauthorized, private.ErrServCommand{
- Results: results,
- Err: fmt.Sprintf("User: %d:%s with Key: %d:%s is not authorized to %s %s/%s.", user.ID, user.Name, key.ID, key.Name, modeString, ownerName, repoName),
+ ctx.JSON(http.StatusUnauthorized, private.Response{
+ UserMsg: fmt.Sprintf("User: %d:%s with Key: %d:%s is not authorized to %s %s/%s.", user.ID, user.Name, key.ID, key.Name, modeString, ownerName, repoName),
})
return
}
@@ -346,24 +326,21 @@ func ServCommand(ctx *context.PrivateContext) {
if !repoExist {
owner, err := user_model.GetUserByName(ctx, ownerName)
if err != nil {
- ctx.JSON(http.StatusInternalServerError, private.ErrServCommand{
- Results: results,
- Err: fmt.Sprintf("Unable to get owner: %s %v", results.OwnerName, err),
+ ctx.JSON(http.StatusInternalServerError, private.Response{
+ Err: fmt.Sprintf("Unable to get owner: %s %v", results.OwnerName, err),
})
return
}
if owner.IsOrganization() && !setting.Repository.EnablePushCreateOrg {
- ctx.JSON(http.StatusForbidden, private.ErrServCommand{
- Results: results,
- Err: "Push to create is not enabled for organizations.",
+ ctx.JSON(http.StatusForbidden, private.Response{
+ UserMsg: "Push to create is not enabled for organizations.",
})
return
}
if !owner.IsOrganization() && !setting.Repository.EnablePushCreateUser {
- ctx.JSON(http.StatusForbidden, private.ErrServCommand{
- Results: results,
- Err: "Push to create is not enabled for users.",
+ ctx.JSON(http.StatusForbidden, private.Response{
+ UserMsg: "Push to create is not enabled for users.",
})
return
}
@@ -371,9 +348,8 @@ func ServCommand(ctx *context.PrivateContext) {
repo, err = repo_service.PushCreateRepo(ctx, user, owner, results.RepoName)
if err != nil {
log.Error("pushCreateRepo: %v", err)
- ctx.JSON(http.StatusNotFound, private.ErrServCommand{
- Results: results,
- Err: fmt.Sprintf("Cannot find repository: %s/%s", results.OwnerName, results.RepoName),
+ ctx.JSON(http.StatusNotFound, private.Response{
+ UserMsg: fmt.Sprintf("Cannot find repository: %s/%s", results.OwnerName, results.RepoName),
})
return
}
@@ -384,16 +360,14 @@ func ServCommand(ctx *context.PrivateContext) {
// Ensure the wiki is enabled before we allow access to it
if _, err := repo.GetUnit(ctx, unit.TypeWiki); err != nil {
if repo_model.IsErrUnitTypeNotExist(err) {
- ctx.JSON(http.StatusForbidden, private.ErrServCommand{
- Results: results,
- Err: "repository wiki is disabled",
+ ctx.JSON(http.StatusForbidden, private.Response{
+ UserMsg: "repository wiki is disabled",
})
return
}
log.Error("Failed to get the wiki unit in %-v Error: %v", repo, err)
- ctx.JSON(http.StatusInternalServerError, private.ErrServCommand{
- Results: results,
- Err: fmt.Sprintf("Failed to get the wiki unit in %s/%s Error: %v", ownerName, repoName, err),
+ ctx.JSON(http.StatusInternalServerError, private.Response{
+ Err: fmt.Sprintf("Failed to get the wiki unit in %s/%s Error: %v", ownerName, repoName, err),
})
return
}
@@ -401,9 +375,8 @@ func ServCommand(ctx *context.PrivateContext) {
// Finally if we're trying to touch the wiki we should init it
if err = wiki_service.InitWiki(ctx, repo); err != nil {
log.Error("Failed to initialize the wiki in %-v Error: %v", repo, err)
- ctx.JSON(http.StatusInternalServerError, private.ErrServCommand{
- Results: results,
- Err: fmt.Sprintf("Failed to initialize the wiki in %s/%s Error: %v", ownerName, repoName, err),
+ ctx.JSON(http.StatusInternalServerError, private.Response{
+ Err: fmt.Sprintf("Failed to initialize the wiki in %s/%s Error: %v", ownerName, repoName, err),
})
return
}
diff --git a/tests/integration/api_private_serv_test.go b/tests/integration/api_private_serv_test.go
index d26935f446..8beec62382 100644
--- a/tests/integration/api_private_serv_test.go
+++ b/tests/integration/api_private_serv_test.go
@@ -43,8 +43,8 @@ func TestAPIPrivateServ(t *testing.T) {
defer cancel()
// Can push to a repo we own
- results, err := private.ServCommand(ctx, 1, "user2", "repo1", perm.AccessModeWrite, "git-upload-pack", "")
- assert.NoError(t, err)
+ results, extra := private.ServCommand(ctx, 1, "user2", "repo1", perm.AccessModeWrite, "git-upload-pack", "")
+ assert.NoError(t, extra.Error)
assert.False(t, results.IsWiki)
assert.Zero(t, results.DeployKeyID)
assert.Equal(t, int64(1), results.KeyID)
@@ -56,18 +56,18 @@ func TestAPIPrivateServ(t *testing.T) {
assert.Equal(t, int64(1), results.RepoID)
// Cannot push to a private repo we're not associated with
- results, err = private.ServCommand(ctx, 1, "user15", "big_test_private_1", perm.AccessModeWrite, "git-upload-pack", "")
- assert.Error(t, err)
+ results, extra = private.ServCommand(ctx, 1, "user15", "big_test_private_1", perm.AccessModeWrite, "git-upload-pack", "")
+ assert.Error(t, extra.Error)
assert.Empty(t, results)
// Cannot pull from a private repo we're not associated with
- results, err = private.ServCommand(ctx, 1, "user15", "big_test_private_1", perm.AccessModeRead, "git-upload-pack", "")
- assert.Error(t, err)
+ results, extra = private.ServCommand(ctx, 1, "user15", "big_test_private_1", perm.AccessModeRead, "git-upload-pack", "")
+ assert.Error(t, extra.Error)
assert.Empty(t, results)
// Can pull from a public repo we're not associated with
- results, err = private.ServCommand(ctx, 1, "user15", "big_test_public_1", perm.AccessModeRead, "git-upload-pack", "")
- assert.NoError(t, err)
+ results, extra = private.ServCommand(ctx, 1, "user15", "big_test_public_1", perm.AccessModeRead, "git-upload-pack", "")
+ assert.NoError(t, extra.Error)
assert.False(t, results.IsWiki)
assert.Zero(t, results.DeployKeyID)
assert.Equal(t, int64(1), results.KeyID)
@@ -79,8 +79,8 @@ func TestAPIPrivateServ(t *testing.T) {
assert.Equal(t, int64(17), results.RepoID)
// Cannot push to a public repo we're not associated with
- results, err = private.ServCommand(ctx, 1, "user15", "big_test_public_1", perm.AccessModeWrite, "git-upload-pack", "")
- assert.Error(t, err)
+ results, extra = private.ServCommand(ctx, 1, "user15", "big_test_public_1", perm.AccessModeWrite, "git-upload-pack", "")
+ assert.Error(t, extra.Error)
assert.Empty(t, results)
// Add reading deploy key
@@ -88,8 +88,8 @@ func TestAPIPrivateServ(t *testing.T) {
assert.NoError(t, err)
// Can pull from repo we're a deploy key for
- results, err = private.ServCommand(ctx, deployKey.KeyID, "user15", "big_test_private_1", perm.AccessModeRead, "git-upload-pack", "")
- assert.NoError(t, err)
+ results, extra = private.ServCommand(ctx, deployKey.KeyID, "user15", "big_test_private_1", perm.AccessModeRead, "git-upload-pack", "")
+ assert.NoError(t, extra.Error)
assert.False(t, results.IsWiki)
assert.NotZero(t, results.DeployKeyID)
assert.Equal(t, deployKey.KeyID, results.KeyID)
@@ -101,18 +101,18 @@ func TestAPIPrivateServ(t *testing.T) {
assert.Equal(t, int64(19), results.RepoID)
// Cannot push to a private repo with reading key
- results, err = private.ServCommand(ctx, deployKey.KeyID, "user15", "big_test_private_1", perm.AccessModeWrite, "git-upload-pack", "")
- assert.Error(t, err)
+ results, extra = private.ServCommand(ctx, deployKey.KeyID, "user15", "big_test_private_1", perm.AccessModeWrite, "git-upload-pack", "")
+ assert.Error(t, extra.Error)
assert.Empty(t, results)
// Cannot pull from a private repo we're not associated with
- results, err = private.ServCommand(ctx, deployKey.ID, "user15", "big_test_private_2", perm.AccessModeRead, "git-upload-pack", "")
- assert.Error(t, err)
+ results, extra = private.ServCommand(ctx, deployKey.ID, "user15", "big_test_private_2", perm.AccessModeRead, "git-upload-pack", "")
+ assert.Error(t, extra.Error)
assert.Empty(t, results)
// Cannot pull from a public repo we're not associated with
- results, err = private.ServCommand(ctx, deployKey.ID, "user15", "big_test_public_1", perm.AccessModeRead, "git-upload-pack", "")
- assert.Error(t, err)
+ results, extra = private.ServCommand(ctx, deployKey.ID, "user15", "big_test_public_1", perm.AccessModeRead, "git-upload-pack", "")
+ assert.Error(t, extra.Error)
assert.Empty(t, results)
// Add writing deploy key
@@ -120,13 +120,13 @@ func TestAPIPrivateServ(t *testing.T) {
assert.NoError(t, err)
// Cannot push to a private repo with reading key
- results, err = private.ServCommand(ctx, deployKey.KeyID, "user15", "big_test_private_1", perm.AccessModeWrite, "git-upload-pack", "")
- assert.Error(t, err)
+ results, extra = private.ServCommand(ctx, deployKey.KeyID, "user15", "big_test_private_1", perm.AccessModeWrite, "git-upload-pack", "")
+ assert.Error(t, extra.Error)
assert.Empty(t, results)
// Can pull from repo we're a writing deploy key for
- results, err = private.ServCommand(ctx, deployKey.KeyID, "user15", "big_test_private_2", perm.AccessModeRead, "git-upload-pack", "")
- assert.NoError(t, err)
+ results, extra = private.ServCommand(ctx, deployKey.KeyID, "user15", "big_test_private_2", perm.AccessModeRead, "git-upload-pack", "")
+ assert.NoError(t, extra.Error)
assert.False(t, results.IsWiki)
assert.NotZero(t, results.DeployKeyID)
assert.Equal(t, deployKey.KeyID, results.KeyID)
@@ -138,8 +138,8 @@ func TestAPIPrivateServ(t *testing.T) {
assert.Equal(t, int64(20), results.RepoID)
// Can push to repo we're a writing deploy key for
- results, err = private.ServCommand(ctx, deployKey.KeyID, "user15", "big_test_private_2", perm.AccessModeWrite, "git-upload-pack", "")
- assert.NoError(t, err)
+ results, extra = private.ServCommand(ctx, deployKey.KeyID, "user15", "big_test_private_2", perm.AccessModeWrite, "git-upload-pack", "")
+ assert.NoError(t, extra.Error)
assert.False(t, results.IsWiki)
assert.NotZero(t, results.DeployKeyID)
assert.Equal(t, deployKey.KeyID, results.KeyID)