Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion clients/resty/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ import (
"github.com/pubgo/funk/v2/retry"

"github.com/pubgo/lava/v2/core/metrics"
"github.com/pubgo/lava/v2/pkg/lava"
"github.com/pubgo/lava/v2/pkg/middleware/accesslog"
"github.com/pubgo/lava/v2/pkg/middleware/metric"
"github.com/pubgo/lava/v2/pkg/middleware/recovery"
"github.com/pubgo/lava/v2/pkg/middleware/serviceinfo"
"github.com/pubgo/lava/v2/pkg/lava"
)

// Params 客户端参数结构
Expand Down
86 changes: 0 additions & 86 deletions clients/resty/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,16 @@ import (
"errors"
"fmt"
"io"
"net/http"
"net/url"
"regexp"
"strconv"
"strings"

"github.com/goccy/go-json"
"github.com/pubgo/funk/v2/convert"
"github.com/pubgo/funk/v2/result"
"github.com/valyala/fasttemplate"
"golang.org/x/net/http/httpguts"
)

// IsRedirect 检查状态码是否为重定向
func IsRedirect(statusCode int) bool {
return statusCode == http.StatusMovedPermanently ||
statusCode == http.StatusFound ||
statusCode == http.StatusSeeOther ||
statusCode == http.StatusTemporaryRedirect ||
statusCode == http.StatusPermanentRedirect
}

// FilterFlags 过滤内容中的标志
func FilterFlags(content string) string {
for i, char := range content {
Expand Down Expand Up @@ -76,60 +64,6 @@ func PathTemplateRun(tpl *fasttemplate.Template, params map[string]any) (string,
})
}

// HeaderGet 获取 HTTP 头
func HeaderGet(h http.Header, key string) string {
if v := h[key]; len(v) > 0 {
return v[0]
}
return ""
}

// HeaderHas 检查 HTTP 头是否存在
func HeaderHas(h http.Header, key string) bool {
_, ok := h[key]
return ok
}

// HasPort 检查字符串是否包含端口
func HasPort(s string) bool {
return strings.LastIndex(s, ":") > strings.LastIndex(s, "]")
}

// RemoveEmptyPort 移除空端口
func RemoveEmptyPort(host string) string {
if HasPort(host) {
return strings.TrimSuffix(host, ":")
}
return host
}

// IsNotToken 检查字符是否不是有效的 HTTP token
func IsNotToken(r rune) bool {
return !httpguts.IsTokenRune(r)
}

// ValidMethod 检查 HTTP 方法是否有效
func ValidMethod(method string) bool {
return len(method) > 0 && strings.IndexFunc(method, IsNotToken) == -1
}

// ValueOrDefault 返回非空值,否则返回默认值
func ValueOrDefault(value, def string) string {
if value != "" {
return value
}
return def
}

// RequestMethodUsuallyLacksBody 检查 HTTP 方法是否通常不需要请求体
func RequestMethodUsuallyLacksBody(method string) bool {
switch method {
case "GET", "HEAD", "DELETE", "OPTIONS", "PROPFIND", "SEARCH":
return true
}
return false
}

// GetBodyReader 获取请求体读取器
func GetBodyReader(rawBody any) (r result.Result[[]byte]) {
switch body := rawBody.(type) {
Expand Down Expand Up @@ -178,26 +112,6 @@ func GetBodyReader(rawBody any) (r result.Result[[]byte]) {
}
}

// CloseBody 关闭请求体
func CloseBody(r *http.Request) error {
if r.Body == nil {
return nil
}
return r.Body.Close()
}

// ErrMissingHost 当请求中没有 Host 或 URL 时返回的错误
var ErrMissingHost = errors.New("http: Request.Write on Request with no Host or URL set")

// ReqWriteExcludeHeader Request.Write 自己处理的头,应该被跳过
var ReqWriteExcludeHeader = map[string]bool{
"Host": true, // not in Header map anyway
"User-Agent": true,
"Content-Length": true,
"Transfer-Encoding": true,
"Trailer": true,
}

// HandleContentType 处理内容类型
func HandleContentType(defaultContentType, configContentType, reqContentType string) (string, error) {
contentType := defaultContentType
Expand Down
104 changes: 104 additions & 0 deletions clients/resty/common_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
package resty

import (
"bytes"
"net/url"
"strings"
"testing"
)

func TestFilterFlags(t *testing.T) {
tests := []struct {
in, want string
}{
{"application/json", "application/json"},
{"application/json; charset=utf-8", "application/json"},
{"text/plain foo", "text/plain"},
{"", ""},
}
for _, tt := range tests {
if got := FilterFlags(tt.in); got != tt.want {
t.Fatalf("FilterFlags(%q)=%q want %q", tt.in, got, tt.want)
}
}
}

func TestToString(t *testing.T) {
tests := []struct {
in any
want string
}{
{"hi", "hi"},
{true, "true"},
{42, "42"},
{int64(7), "7"},
{uint(3), "3"},
{struct{ A int }{1}, "{1}"},
}
for _, tt := range tests {
if got := ToString(tt.in); got != tt.want {
t.Fatalf("ToString(%v)=%q want %q", tt.in, got, tt.want)
}
}
}

func TestHandleContentType(t *testing.T) {
got, err := HandleContentType("application/json", "", "")
if err != nil || got != "application/json" {
t.Fatalf("default=%q err=%v", got, err)
}
got, err = HandleContentType("application/json", "text/plain", "")
if err != nil || got != "text/plain" {
t.Fatalf("config=%q err=%v", got, err)
}
got, err = HandleContentType("application/json", "text/plain", "application/xml")
if err != nil || got != "application/xml" {
t.Fatalf("req=%q err=%v", got, err)
}
if _, err := HandleContentType("", "", ""); err == nil {
t.Fatal("expected empty content-type error")
}
}

func TestPathTemplate(t *testing.T) {
tpl, err := CreatePathTemplate("/users/{id}/posts/{pid}")
if err != nil {
t.Fatal(err)
}
got, err := PathTemplateRun(tpl, map[string]any{"id": 42, "pid": "abc"})
if err != nil {
t.Fatal(err)
}
if got != "/users/42/posts/abc" {
t.Fatalf("got=%q", got)
}
}

func TestGetBodyReader(t *testing.T) {
if GetBodyReader(nil).IsErr() {
t.Fatal("nil body should succeed")
}
if !bytes.Equal(GetBodyReader([]byte("hi")).Unwrap(), []byte("hi")) {
t.Fatal("[]byte")
}
if !bytes.Equal(GetBodyReader("hi").Unwrap(), []byte("hi")) {
t.Fatal("string")
}
if !bytes.Equal(GetBodyReader(bytes.NewBufferString("buf")).Unwrap(), []byte("buf")) {
t.Fatal("buffer")
}
vals := url.Values{"a": {"1"}}
if got := string(GetBodyReader(vals).Unwrap()); got != "a=1" {
t.Fatalf("url.Values=%q", got)
}
if got := string(GetBodyReader(strings.NewReader("reader")).Unwrap()); got != "reader" {
t.Fatalf("reader=%q", got)
}
type payload struct {
Name string `json:"name"`
}
raw := GetBodyReader(payload{Name: "x"}).Unwrap()
if !bytes.Contains(raw, []byte(`"name":"x"`)) {
t.Fatalf("json=%s", raw)
}
}
Loading
Loading