diff --git a/kernel/api/network.go b/kernel/api/network.go new file mode 100644 index 000000000..f4854ddc2 --- /dev/null +++ b/kernel/api/network.go @@ -0,0 +1,114 @@ +// SiYuan - Refactor your thinking +// Copyright (c) 2020-present, b3log.org +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package api + +import ( + "fmt" + "io" + "net/http" + "net/url" + "strings" + "time" + + "github.com/88250/gulu" + "github.com/gin-gonic/gin" + "github.com/imroc/req/v3" + "github.com/siyuan-note/siyuan/kernel/util" +) + +func forwardProxy(c *gin.Context) { + ret := gulu.Ret.NewResult() + defer c.JSON(http.StatusOK, ret) + + arg, ok := util.JsonArg(c, ret) + if !ok { + return + } + + destURL := arg["url"].(string) + if _, e := url.ParseRequestURI(destURL); nil != e { + ret.Code = -1 + ret.Msg = "invalid [url]" + return + } + + method := strings.ToUpper(arg["method"].(string)) + timeoutArg := arg["timeout"] + timeout := 7 * 1000 + if nil != timeoutArg { + timeout = int(timeoutArg.(float64)) + if 1 > timeout { + timeout = 7 * 1000 + } + } + + client := req.C() + client.SetTimeout(time.Duration(timeout) * time.Millisecond) + request := client.R() + headers := arg["headers"].([]interface{}) + for _, pair := range headers { + for k, v := range pair.(map[string]interface{}) { + request.SetHeader(k, fmt.Sprintf("%s", v)) + } + } + + contentType := arg["contentType"] + if nil != contentType && "" != contentType { + request.SetHeader("Content-Type", contentType.(string)) + } + + if "POST" == method { + request.SetBody(arg["payload"]) + } + + started := time.Now() + resp, err := request.Send(method, destURL) + if nil != err { + ret.Code = -1 + ret.Msg = "forward request failed: " + err.Error() + return + } + + bodyData, err := io.ReadAll(resp.Body) + if nil != err { + ret.Code = -1 + ret.Msg = "read response body failed: " + err.Error() + return + } + body := string(bodyData) + elapsed := time.Now().Sub(started) + + data := map[string]interface{}{ + "url": destURL, + "status": resp.StatusCode, + "contentType": resp.GetHeader("content-type"), + "body": body, + "headers": resp.Header, + "elapsed": elapsed.Milliseconds(), + } + ret.Data = data + + //shortBody := "" + //if 64 > len(body) { + // shortBody = body + //} else { + // shortBody = body[:64] + //} + // + //logging.LogInfof("elapsed [%.1fs], length [%d], request [url=%s, headers=%s, content-type=%s, body=%s], status [%d], body [%s]", + // elapsed.Seconds(), len(bodyData), data["url"], headers, contentType, arg["payload"], data["status"], shortBody) +} diff --git a/kernel/api/router.go b/kernel/api/router.go index fa69ad0a9..79074fc53 100644 --- a/kernel/api/router.go +++ b/kernel/api/router.go @@ -364,4 +364,6 @@ func ServeAPI(ginServer *gin.Engine) { ginServer.Handle("POST", "/api/petal/loadPetals", model.CheckAuth, model.CheckReadonly, loadPetals) ginServer.Handle("POST", "/api/petal/setPetalEnabled", model.CheckAuth, model.CheckReadonly, setPetalEnabled) + + ginServer.Handle("POST", "/api/network/forwardProxy", model.CheckAuth, model.CheckReadonly, forwardProxy) }