Merge branch 'develop' into session-filter
This commit is contained in:
commit
7366b48a43
@ -74,7 +74,7 @@ func oldMiddlewareToNew(mws []MiddleWare) []web.MiddleWare {
|
||||
// beego.Router("/api/update",&RestController{},"put:UpdateFood")
|
||||
// beego.Router("/api/delete",&RestController{},"delete:DeleteFood")
|
||||
func Router(rootpath string, c ControllerInterface, mappingMethods ...string) *App {
|
||||
return (*App)(web.Router(rootpath, c, mappingMethods...))
|
||||
return (*App)(web.Router(rootpath, c, web.SetRouterMethods(c, mappingMethods...)))
|
||||
}
|
||||
|
||||
// UnregisterFixedRoute unregisters the route with the specified fixedRoute. It is particularly useful
|
||||
|
||||
@ -87,7 +87,7 @@ func NewControllerRegister() *ControllerRegister {
|
||||
// Add("/api",&RestController{},"get,post:ApiFunc"
|
||||
// Add("/simple",&SimpleController{},"get:GetFunc;post:PostFunc")
|
||||
func (p *ControllerRegister) Add(pattern string, c ControllerInterface, mappingMethods ...string) {
|
||||
(*web.ControllerRegister)(p).Add(pattern, c, mappingMethods...)
|
||||
(*web.ControllerRegister)(p).Add(pattern, c, web.SetRouterMethods(c, mappingMethods...))
|
||||
}
|
||||
|
||||
// Include only when the Runmode is dev will generate router file in the router/auto.go from the controller
|
||||
|
||||
36
client/httplib/http_response_test.go
Normal file
36
client/httplib/http_response_test.go
Normal file
@ -0,0 +1,36 @@
|
||||
// Copyright 2020 beego
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package httplib
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
|
||||
func TestNewHttpResponseWithJsonBody(t *testing.T) {
|
||||
// string
|
||||
resp := NewHttpResponseWithJsonBody("{}")
|
||||
assert.Equal(t, int64(2), resp.ContentLength)
|
||||
|
||||
resp = NewHttpResponseWithJsonBody([]byte("{}"))
|
||||
assert.Equal(t, int64(2), resp.ContentLength)
|
||||
|
||||
resp = NewHttpResponseWithJsonBody(&user{
|
||||
Name: "Tom",
|
||||
})
|
||||
assert.True(t, resp.ContentLength > 0)
|
||||
}
|
||||
@ -44,49 +44,22 @@ import (
|
||||
"mime/multipart"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/cookiejar"
|
||||
"net/http/httputil"
|
||||
"net/url"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
var defaultSetting = BeegoHTTPSettings{
|
||||
UserAgent: "beegoServer",
|
||||
ConnectTimeout: 60 * time.Second,
|
||||
ReadWriteTimeout: 60 * time.Second,
|
||||
Gzip: true,
|
||||
DumpBody: true,
|
||||
FilterChains: []FilterChain{mockFilter.FilterChain},
|
||||
}
|
||||
|
||||
var defaultCookieJar http.CookieJar
|
||||
var settingMutex sync.Mutex
|
||||
|
||||
// it will be the last filter and execute request.Do
|
||||
var doRequestFilter = func(ctx context.Context, req *BeegoHTTPRequest) (*http.Response, error) {
|
||||
return req.doRequest(ctx)
|
||||
}
|
||||
|
||||
// createDefaultCookie creates a global cookiejar to store cookies.
|
||||
func createDefaultCookie() {
|
||||
settingMutex.Lock()
|
||||
defer settingMutex.Unlock()
|
||||
defaultCookieJar, _ = cookiejar.New(nil)
|
||||
}
|
||||
|
||||
// SetDefaultSetting overwrites default settings
|
||||
func SetDefaultSetting(setting BeegoHTTPSettings) {
|
||||
settingMutex.Lock()
|
||||
defer settingMutex.Unlock()
|
||||
defaultSetting = setting
|
||||
}
|
||||
|
||||
// NewBeegoRequest returns *BeegoHttpRequest with specific method
|
||||
func NewBeegoRequest(rawurl, method string) *BeegoHTTPRequest {
|
||||
var resp http.Response
|
||||
@ -137,23 +110,7 @@ func Head(url string) *BeegoHTTPRequest {
|
||||
return NewBeegoRequest(url, "HEAD")
|
||||
}
|
||||
|
||||
// BeegoHTTPSettings is the http.Client setting
|
||||
type BeegoHTTPSettings struct {
|
||||
ShowDebug bool
|
||||
UserAgent string
|
||||
ConnectTimeout time.Duration
|
||||
ReadWriteTimeout time.Duration
|
||||
TLSClientConfig *tls.Config
|
||||
Proxy func(*http.Request) (*url.URL, error)
|
||||
Transport http.RoundTripper
|
||||
CheckRedirect func(req *http.Request, via []*http.Request) error
|
||||
EnableCookie bool
|
||||
Gzip bool
|
||||
DumpBody bool
|
||||
Retries int // if set to -1 means will retry forever
|
||||
RetryDelay time.Duration
|
||||
FilterChains []FilterChain
|
||||
}
|
||||
|
||||
|
||||
// BeegoHTTPRequest provides more useful methods than http.Request for requesting a url.
|
||||
type BeegoHTTPRequest struct {
|
||||
@ -362,6 +319,9 @@ func (b *BeegoHTTPRequest) XMLBody(obj interface{}) (*BeegoHTTPRequest, error) {
|
||||
return b, err
|
||||
}
|
||||
b.req.Body = ioutil.NopCloser(bytes.NewReader(byts))
|
||||
b.req.GetBody = func() (io.ReadCloser, error) {
|
||||
return ioutil.NopCloser(bytes.NewReader(byts)), nil
|
||||
}
|
||||
b.req.ContentLength = int64(len(byts))
|
||||
b.req.Header.Set("Content-Type", "application/xml")
|
||||
}
|
||||
|
||||
@ -300,3 +300,81 @@ func TestAddFilter(t *testing.T) {
|
||||
r := Get("http://beego.me")
|
||||
assert.Equal(t, 1, len(req.setting.FilterChains)-len(r.setting.FilterChains))
|
||||
}
|
||||
|
||||
func TestHead(t *testing.T) {
|
||||
req := Head("http://beego.me")
|
||||
assert.NotNil(t, req)
|
||||
assert.Equal(t, "HEAD", req.req.Method)
|
||||
}
|
||||
|
||||
func TestDelete(t *testing.T) {
|
||||
req := Delete("http://beego.me")
|
||||
assert.NotNil(t, req)
|
||||
assert.Equal(t, "DELETE", req.req.Method)
|
||||
}
|
||||
|
||||
func TestPost(t *testing.T) {
|
||||
req := Post("http://beego.me")
|
||||
assert.NotNil(t, req)
|
||||
assert.Equal(t, "POST", req.req.Method)
|
||||
}
|
||||
|
||||
func TestNewBeegoRequest(t *testing.T) {
|
||||
req := NewBeegoRequest("http://beego.me", "GET")
|
||||
assert.NotNil(t, req)
|
||||
assert.Equal(t, "GET", req.req.Method)
|
||||
}
|
||||
|
||||
func TestPut(t *testing.T) {
|
||||
req := Put("http://beego.me")
|
||||
assert.NotNil(t, req)
|
||||
assert.Equal(t, "PUT", req.req.Method)
|
||||
}
|
||||
|
||||
func TestBeegoHTTPRequest_Header(t *testing.T) {
|
||||
req := Post("http://beego.me")
|
||||
key, value := "test-header", "test-header-value"
|
||||
req.Header(key, value)
|
||||
assert.Equal(t, value, req.req.Header.Get(key))
|
||||
}
|
||||
|
||||
func TestBeegoHTTPRequest_SetHost(t *testing.T) {
|
||||
req := Post("http://beego.me")
|
||||
host := "test-hose"
|
||||
req.SetHost(host)
|
||||
assert.Equal(t, host, req.req.Host)
|
||||
}
|
||||
|
||||
func TestBeegoHTTPRequest_Param(t *testing.T) {
|
||||
req := Post("http://beego.me")
|
||||
key, value := "test-param", "test-param-value"
|
||||
req.Param(key, value)
|
||||
assert.Equal(t, value, req.params[key][0])
|
||||
|
||||
value1 := "test-param-value-1"
|
||||
req.Param(key, value1)
|
||||
assert.Equal(t, value1, req.params[key][1])
|
||||
}
|
||||
|
||||
func TestBeegoHTTPRequest_Body(t *testing.T) {
|
||||
req := Post("http://beego.me")
|
||||
body := `hello, world`
|
||||
req.Body([]byte(body))
|
||||
assert.Equal(t, int64(len(body)), req.req.ContentLength)
|
||||
assert.NotNil(t, req.req.GetBody)
|
||||
}
|
||||
|
||||
|
||||
type user struct {
|
||||
Name string `xml:"name"`
|
||||
}
|
||||
func TestBeegoHTTPRequest_XMLBody(t *testing.T) {
|
||||
req := Post("http://beego.me")
|
||||
body := &user{
|
||||
Name: "Tom",
|
||||
}
|
||||
_, err := req.XMLBody(body)
|
||||
assert.True(t, req.req.ContentLength > 0)
|
||||
assert.Nil(t, err)
|
||||
assert.NotNil(t, req.req.GetBody)
|
||||
}
|
||||
@ -12,17 +12,22 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package httplib
|
||||
package mock
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"github.com/beego/beego/v2/client/httplib"
|
||||
"github.com/beego/beego/v2/core/logs"
|
||||
)
|
||||
|
||||
const mockCtxKey = "beego-httplib-mock"
|
||||
|
||||
func init() {
|
||||
InitMockSetting()
|
||||
}
|
||||
|
||||
type Stub interface {
|
||||
Mock(cond RequestCondition, resp *http.Response, err error)
|
||||
Clear()
|
||||
@ -31,6 +36,10 @@ type Stub interface {
|
||||
|
||||
var mockFilter = &MockResponseFilter{}
|
||||
|
||||
func InitMockSetting() {
|
||||
httplib.AddDefaultFilter(mockFilter.FilterChain)
|
||||
}
|
||||
|
||||
func StartMock() Stub {
|
||||
return mockFilter
|
||||
}
|
||||
@ -12,17 +12,19 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package httplib
|
||||
package mock
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/textproto"
|
||||
"regexp"
|
||||
|
||||
"github.com/beego/beego/v2/client/httplib"
|
||||
)
|
||||
|
||||
type RequestCondition interface {
|
||||
Match(ctx context.Context, req *BeegoHTTPRequest) bool
|
||||
Match(ctx context.Context, req *httplib.BeegoHTTPRequest) bool
|
||||
}
|
||||
|
||||
// reqCondition create condition
|
||||
@ -54,7 +56,7 @@ func NewSimpleCondition(path string, opts ...simpleConditionOption) *SimpleCondi
|
||||
return sc
|
||||
}
|
||||
|
||||
func (sc *SimpleCondition) Match(ctx context.Context, req *BeegoHTTPRequest) bool {
|
||||
func (sc *SimpleCondition) Match(ctx context.Context, req *httplib.BeegoHTTPRequest) bool {
|
||||
res := true
|
||||
if len(sc.path) > 0 {
|
||||
res = sc.matchPath(ctx, req)
|
||||
@ -70,12 +72,12 @@ func (sc *SimpleCondition) Match(ctx context.Context, req *BeegoHTTPRequest) boo
|
||||
sc.matchBodyFields(ctx, req)
|
||||
}
|
||||
|
||||
func (sc *SimpleCondition) matchPath(ctx context.Context, req *BeegoHTTPRequest) bool {
|
||||
func (sc *SimpleCondition) matchPath(ctx context.Context, req *httplib.BeegoHTTPRequest) bool {
|
||||
path := req.GetRequest().URL.Path
|
||||
return path == sc.path
|
||||
}
|
||||
|
||||
func (sc *SimpleCondition) matchPathReg(ctx context.Context, req *BeegoHTTPRequest) bool {
|
||||
func (sc *SimpleCondition) matchPathReg(ctx context.Context, req *httplib.BeegoHTTPRequest) bool {
|
||||
path := req.GetRequest().URL.Path
|
||||
if b, err := regexp.Match(sc.pathReg, []byte(path)); err == nil {
|
||||
return b
|
||||
@ -83,7 +85,7 @@ func (sc *SimpleCondition) matchPathReg(ctx context.Context, req *BeegoHTTPReque
|
||||
return false
|
||||
}
|
||||
|
||||
func (sc *SimpleCondition) matchQuery(ctx context.Context, req *BeegoHTTPRequest) bool {
|
||||
func (sc *SimpleCondition) matchQuery(ctx context.Context, req *httplib.BeegoHTTPRequest) bool {
|
||||
qs := req.GetRequest().URL.Query()
|
||||
for k, v := range sc.query {
|
||||
if uv, ok := qs[k]; !ok || uv[0] != v {
|
||||
@ -93,7 +95,7 @@ func (sc *SimpleCondition) matchQuery(ctx context.Context, req *BeegoHTTPRequest
|
||||
return true
|
||||
}
|
||||
|
||||
func (sc *SimpleCondition) matchHeader(ctx context.Context, req *BeegoHTTPRequest) bool {
|
||||
func (sc *SimpleCondition) matchHeader(ctx context.Context, req *httplib.BeegoHTTPRequest) bool {
|
||||
headers := req.GetRequest().Header
|
||||
for k, v := range sc.header {
|
||||
if uv, ok := headers[k]; !ok || uv[0] != v {
|
||||
@ -103,7 +105,7 @@ func (sc *SimpleCondition) matchHeader(ctx context.Context, req *BeegoHTTPReques
|
||||
return true
|
||||
}
|
||||
|
||||
func (sc *SimpleCondition) matchBodyFields(ctx context.Context, req *BeegoHTTPRequest) bool {
|
||||
func (sc *SimpleCondition) matchBodyFields(ctx context.Context, req *httplib.BeegoHTTPRequest) bool {
|
||||
if len(sc.body) == 0 {
|
||||
return true
|
||||
}
|
||||
@ -135,7 +137,7 @@ func (sc *SimpleCondition) matchBodyFields(ctx context.Context, req *BeegoHTTPRe
|
||||
return true
|
||||
}
|
||||
|
||||
func (sc *SimpleCondition) matchMethod(ctx context.Context, req *BeegoHTTPRequest) bool {
|
||||
func (sc *SimpleCondition) matchMethod(ctx context.Context, req *httplib.BeegoHTTPRequest) bool {
|
||||
if len(sc.method) > 0 {
|
||||
return sc.method == req.GetRequest().Method
|
||||
}
|
||||
@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package httplib
|
||||
package mock
|
||||
|
||||
import (
|
||||
"context"
|
||||
@ -20,6 +20,7 @@ import (
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/beego/beego/v2/client/httplib"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@ -28,37 +29,37 @@ func init() {
|
||||
|
||||
func TestSimpleCondition_MatchPath(t *testing.T) {
|
||||
sc := NewSimpleCondition("/abc/s")
|
||||
res := sc.Match(context.Background(), Get("http://localhost:8080/abc/s"))
|
||||
res := sc.Match(context.Background(), httplib.Get("http://localhost:8080/abc/s"))
|
||||
assert.True(t, res)
|
||||
}
|
||||
|
||||
func TestSimpleCondition_MatchQuery(t *testing.T) {
|
||||
k, v := "my-key", "my-value"
|
||||
sc := NewSimpleCondition("/abc/s")
|
||||
res := sc.Match(context.Background(), Get("http://localhost:8080/abc/s?my-key=my-value"))
|
||||
res := sc.Match(context.Background(), httplib.Get("http://localhost:8080/abc/s?my-key=my-value"))
|
||||
assert.True(t, res)
|
||||
|
||||
sc = NewSimpleCondition("/abc/s", WithQuery(k, v))
|
||||
res = sc.Match(context.Background(), Get("http://localhost:8080/abc/s?my-key=my-value"))
|
||||
res = sc.Match(context.Background(), httplib.Get("http://localhost:8080/abc/s?my-key=my-value"))
|
||||
assert.True(t, res)
|
||||
|
||||
res = sc.Match(context.Background(), Get("http://localhost:8080/abc/s?my-key=my-valuesss"))
|
||||
res = sc.Match(context.Background(), httplib.Get("http://localhost:8080/abc/s?my-key=my-valuesss"))
|
||||
assert.False(t, res)
|
||||
|
||||
res = sc.Match(context.Background(), Get("http://localhost:8080/abc/s?my-key-a=my-value"))
|
||||
res = sc.Match(context.Background(), httplib.Get("http://localhost:8080/abc/s?my-key-a=my-value"))
|
||||
assert.False(t, res)
|
||||
|
||||
res = sc.Match(context.Background(), Get("http://localhost:8080/abc/s?my-key=my-value&abc=hello"))
|
||||
res = sc.Match(context.Background(), httplib.Get("http://localhost:8080/abc/s?my-key=my-value&abc=hello"))
|
||||
assert.True(t, res)
|
||||
}
|
||||
|
||||
func TestSimpleCondition_MatchHeader(t *testing.T) {
|
||||
k, v := "my-header", "my-header-value"
|
||||
sc := NewSimpleCondition("/abc/s")
|
||||
req := Get("http://localhost:8080/abc/s")
|
||||
req := httplib.Get("http://localhost:8080/abc/s")
|
||||
assert.True(t, sc.Match(context.Background(), req))
|
||||
|
||||
req = Get("http://localhost:8080/abc/s")
|
||||
req = httplib.Get("http://localhost:8080/abc/s")
|
||||
req.Header(k, v)
|
||||
assert.True(t, sc.Match(context.Background(), req))
|
||||
|
||||
@ -73,7 +74,7 @@ func TestSimpleCondition_MatchHeader(t *testing.T) {
|
||||
func TestSimpleCondition_MatchBodyField(t *testing.T) {
|
||||
|
||||
sc := NewSimpleCondition("/abc/s")
|
||||
req := Post("http://localhost:8080/abc/s")
|
||||
req := httplib.Post("http://localhost:8080/abc/s")
|
||||
|
||||
assert.True(t, sc.Match(context.Background(), req))
|
||||
|
||||
@ -102,7 +103,7 @@ func TestSimpleCondition_MatchBodyField(t *testing.T) {
|
||||
|
||||
func TestSimpleCondition_Match(t *testing.T) {
|
||||
sc := NewSimpleCondition("/abc/s")
|
||||
req := Post("http://localhost:8080/abc/s")
|
||||
req := httplib.Post("http://localhost:8080/abc/s")
|
||||
|
||||
assert.True(t, sc.Match(context.Background(), req))
|
||||
|
||||
@ -115,9 +116,9 @@ func TestSimpleCondition_Match(t *testing.T) {
|
||||
|
||||
func TestSimpleCondition_MatchPathReg(t *testing.T) {
|
||||
sc := NewSimpleCondition("", WithPathReg(`\/abc\/.*`))
|
||||
req := Post("http://localhost:8080/abc/s")
|
||||
req := httplib.Post("http://localhost:8080/abc/s")
|
||||
assert.True(t, sc.Match(context.Background(), req))
|
||||
|
||||
req = Post("http://localhost:8080/abcd/s")
|
||||
req = httplib.Post("http://localhost:8080/abcd/s")
|
||||
assert.False(t, sc.Match(context.Background(), req))
|
||||
}
|
||||
@ -12,12 +12,13 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package httplib
|
||||
package mock
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/beego/beego/v2/client/httplib"
|
||||
)
|
||||
|
||||
// MockResponse will return mock response if find any suitable mock data
|
||||
@ -32,13 +33,10 @@ func NewMockResponseFilter() *MockResponseFilter {
|
||||
}
|
||||
}
|
||||
|
||||
func (m *MockResponseFilter) FilterChain(next Filter) Filter {
|
||||
return func(ctx context.Context, req *BeegoHTTPRequest) (*http.Response, error) {
|
||||
|
||||
func (m *MockResponseFilter) FilterChain(next httplib.Filter) httplib.Filter {
|
||||
return func(ctx context.Context, req *httplib.BeegoHTTPRequest) (*http.Response, error) {
|
||||
ms := mockFromCtx(ctx)
|
||||
ms = append(ms, m.ms...)
|
||||
|
||||
fmt.Printf("url: %s, mock: %d \n", req.url, len(ms))
|
||||
for _, mock := range ms {
|
||||
if mock.cond.Match(ctx, req) {
|
||||
return mock.resp, mock.err
|
||||
@ -12,20 +12,22 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package httplib
|
||||
package mock
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/beego/beego/v2/client/httplib"
|
||||
)
|
||||
|
||||
func TestMockResponseFilter_FilterChain(t *testing.T) {
|
||||
req := Get("http://localhost:8080/abc/s")
|
||||
req := httplib.Get("http://localhost:8080/abc/s")
|
||||
ft := NewMockResponseFilter()
|
||||
|
||||
expectedResp := NewHttpResponseWithJsonBody(`{}`)
|
||||
expectedResp := httplib.NewHttpResponseWithJsonBody(`{}`)
|
||||
expectedErr := errors.New("expected error")
|
||||
ft.Mock(NewSimpleCondition("/abc/s"), expectedResp, expectedErr)
|
||||
|
||||
@ -35,16 +37,16 @@ func TestMockResponseFilter_FilterChain(t *testing.T) {
|
||||
assert.Equal(t, expectedErr, err)
|
||||
assert.Equal(t, expectedResp, resp)
|
||||
|
||||
req = Get("http://localhost:8080/abcd/s")
|
||||
req = httplib.Get("http://localhost:8080/abcd/s")
|
||||
req.AddFilters(ft.FilterChain)
|
||||
|
||||
resp, err = req.DoRequest()
|
||||
assert.NotEqual(t, expectedErr, err)
|
||||
assert.NotEqual(t, expectedResp, resp)
|
||||
|
||||
req = Get("http://localhost:8080/abc/s")
|
||||
req = httplib.Get("http://localhost:8080/abc/s")
|
||||
req.AddFilters(ft.FilterChain)
|
||||
expectedResp1 := NewHttpResponseWithJsonBody(map[string]string{})
|
||||
expectedResp1 := httplib.NewHttpResponseWithJsonBody(map[string]string{})
|
||||
expectedErr1 := errors.New("expected error")
|
||||
ft.Mock(NewSimpleCondition("/abc/abs/bbc"), expectedResp1, expectedErr1)
|
||||
|
||||
@ -52,7 +54,7 @@ func TestMockResponseFilter_FilterChain(t *testing.T) {
|
||||
assert.Equal(t, expectedErr, err)
|
||||
assert.Equal(t, expectedResp, resp)
|
||||
|
||||
req = Get("http://localhost:8080/abc/abs/bbc")
|
||||
req = httplib.Get("http://localhost:8080/abc/abs/bbc")
|
||||
req.AddFilters(ft.FilterChain)
|
||||
ft.Mock(NewSimpleCondition("/abc/abs/bbc"), expectedResp1, expectedErr1)
|
||||
resp, err = req.DoRequest()
|
||||
@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package httplib
|
||||
package mock
|
||||
|
||||
import (
|
||||
"context"
|
||||
@ -21,16 +21,18 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/beego/beego/v2/client/httplib"
|
||||
)
|
||||
|
||||
func TestStartMock(t *testing.T) {
|
||||
|
||||
defaultSetting.FilterChains = []FilterChain{mockFilter.FilterChain}
|
||||
// httplib.defaultSetting.FilterChains = []httplib.FilterChain{mockFilter.FilterChain}
|
||||
|
||||
stub := StartMock()
|
||||
// defer stub.Clear()
|
||||
|
||||
expectedResp := NewHttpResponseWithJsonBody([]byte(`{}`))
|
||||
expectedResp := httplib.NewHttpResponseWithJsonBody([]byte(`{}`))
|
||||
expectedErr := errors.New("expected err")
|
||||
|
||||
stub.Mock(NewSimpleCondition("/abc"), expectedResp, expectedErr)
|
||||
@ -45,14 +47,14 @@ func TestStartMock(t *testing.T) {
|
||||
// TestStartMock_Isolation Test StartMock that
|
||||
// mock only work for this request
|
||||
func TestStartMock_Isolation(t *testing.T) {
|
||||
defaultSetting.FilterChains = []FilterChain{mockFilter.FilterChain}
|
||||
// httplib.defaultSetting.FilterChains = []httplib.FilterChain{mockFilter.FilterChain}
|
||||
// setup global stub
|
||||
stub := StartMock()
|
||||
globalMockResp := NewHttpResponseWithJsonBody([]byte(`{}`))
|
||||
globalMockResp := httplib.NewHttpResponseWithJsonBody([]byte(`{}`))
|
||||
globalMockErr := errors.New("expected err")
|
||||
stub.Mock(NewSimpleCondition("/abc"), globalMockResp, globalMockErr)
|
||||
|
||||
expectedResp := NewHttpResponseWithJsonBody(struct {
|
||||
expectedResp := httplib.NewHttpResponseWithJsonBody(struct {
|
||||
A string `json:"a"`
|
||||
}{
|
||||
A: "aaa",
|
||||
@ -67,9 +69,9 @@ func TestStartMock_Isolation(t *testing.T) {
|
||||
}
|
||||
|
||||
func OriginnalCodeUsingHttplibPassCtx(ctx context.Context) (*http.Response, error) {
|
||||
return Get("http://localhost:7777/abc").DoRequestWithCtx(ctx)
|
||||
return httplib.Get("http://localhost:7777/abc").DoRequestWithCtx(ctx)
|
||||
}
|
||||
|
||||
func OriginalCodeUsingHttplib() (*http.Response, error){
|
||||
return Get("http://localhost:7777/abc").DoRequest()
|
||||
return httplib.Get("http://localhost:7777/abc").DoRequest()
|
||||
}
|
||||
81
client/httplib/setting.go
Normal file
81
client/httplib/setting.go
Normal file
@ -0,0 +1,81 @@
|
||||
// Copyright 2020 beego
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package httplib
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"net/http"
|
||||
"net/http/cookiejar"
|
||||
"net/url"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// BeegoHTTPSettings is the http.Client setting
|
||||
type BeegoHTTPSettings struct {
|
||||
ShowDebug bool
|
||||
UserAgent string
|
||||
ConnectTimeout time.Duration
|
||||
ReadWriteTimeout time.Duration
|
||||
TLSClientConfig *tls.Config
|
||||
Proxy func(*http.Request) (*url.URL, error)
|
||||
Transport http.RoundTripper
|
||||
CheckRedirect func(req *http.Request, via []*http.Request) error
|
||||
EnableCookie bool
|
||||
Gzip bool
|
||||
DumpBody bool
|
||||
Retries int // if set to -1 means will retry forever
|
||||
RetryDelay time.Duration
|
||||
FilterChains []FilterChain
|
||||
}
|
||||
|
||||
// createDefaultCookie creates a global cookiejar to store cookies.
|
||||
func createDefaultCookie() {
|
||||
settingMutex.Lock()
|
||||
defer settingMutex.Unlock()
|
||||
defaultCookieJar, _ = cookiejar.New(nil)
|
||||
}
|
||||
|
||||
// SetDefaultSetting overwrites default settings
|
||||
// Keep in mind that when you invoke the SetDefaultSetting
|
||||
// some methods invoked before SetDefaultSetting
|
||||
func SetDefaultSetting(setting BeegoHTTPSettings) {
|
||||
settingMutex.Lock()
|
||||
defer settingMutex.Unlock()
|
||||
defaultSetting = setting
|
||||
}
|
||||
|
||||
var defaultSetting = BeegoHTTPSettings{
|
||||
UserAgent: "beegoServer",
|
||||
ConnectTimeout: 60 * time.Second,
|
||||
ReadWriteTimeout: 60 * time.Second,
|
||||
Gzip: true,
|
||||
DumpBody: true,
|
||||
FilterChains: make([]FilterChain, 0, 4),
|
||||
}
|
||||
|
||||
var defaultCookieJar http.CookieJar
|
||||
var settingMutex sync.Mutex
|
||||
|
||||
// AddDefaultFilter add a new filter into defaultSetting
|
||||
// Be careful about using this method if you invoke SetDefaultSetting somewhere
|
||||
func AddDefaultFilter(fc FilterChain) {
|
||||
settingMutex.Lock()
|
||||
defer settingMutex.Unlock()
|
||||
if defaultSetting.FilterChains == nil {
|
||||
defaultSetting.FilterChains = make([]FilterChain, 0, 4)
|
||||
}
|
||||
defaultSetting.FilterChains = append(defaultSetting.FilterChains, fc)
|
||||
}
|
||||
@ -69,8 +69,8 @@ func (p *PatternLogFormatter) ToString(lm *LogMsg) string {
|
||||
'm': lm.Msg,
|
||||
'n': strconv.Itoa(lm.LineNumber),
|
||||
'l': strconv.Itoa(lm.Level),
|
||||
't': levelPrefix[lm.Level-1],
|
||||
'T': levelNames[lm.Level-1],
|
||||
't': levelPrefix[lm.Level],
|
||||
'T': levelNames[lm.Level],
|
||||
'F': lm.FilePath,
|
||||
}
|
||||
_, m['f'] = path.Split(lm.FilePath)
|
||||
|
||||
@ -88,7 +88,7 @@ func TestPatternLogFormatter(t *testing.T) {
|
||||
}
|
||||
got := tes.ToString(lm)
|
||||
want := lm.FilePath + ":" + strconv.Itoa(lm.LineNumber) + "|" +
|
||||
when.Format(tes.WhenFormat) + levelPrefix[lm.Level-1] + ">> " + lm.Msg
|
||||
when.Format(tes.WhenFormat) + levelPrefix[lm.Level] + ">> " + lm.Msg
|
||||
if got != want {
|
||||
t.Errorf("want %s, got %s", want, got)
|
||||
}
|
||||
|
||||
@ -112,13 +112,13 @@ func registerAdmin() error {
|
||||
HttpServer: NewHttpServerWithCfg(BConfig),
|
||||
}
|
||||
// keep in mind that all data should be html escaped to avoid XSS attack
|
||||
beeAdminApp.Router("/", c, "get:AdminIndex")
|
||||
beeAdminApp.Router("/qps", c, "get:QpsIndex")
|
||||
beeAdminApp.Router("/prof", c, "get:ProfIndex")
|
||||
beeAdminApp.Router("/healthcheck", c, "get:Healthcheck")
|
||||
beeAdminApp.Router("/task", c, "get:TaskStatus")
|
||||
beeAdminApp.Router("/listconf", c, "get:ListConf")
|
||||
beeAdminApp.Router("/metrics", c, "get:PrometheusMetrics")
|
||||
beeAdminApp.Router("/", c, SetRouterMethods(c, "get:AdminIndex"))
|
||||
beeAdminApp.Router("/qps", c, SetRouterMethods(c, "get:QpsIndex"))
|
||||
beeAdminApp.Router("/prof", c, SetRouterMethods(c, "get:ProfIndex"))
|
||||
beeAdminApp.Router("/healthcheck", c, SetRouterMethods(c, "get:Healthcheck"))
|
||||
beeAdminApp.Router("/task", c, SetRouterMethods(c, "get:TaskStatus"))
|
||||
beeAdminApp.Router("/listconf", c, SetRouterMethods(c, "get:ListConf"))
|
||||
beeAdminApp.Router("/metrics", c, SetRouterMethods(c, "get:PrometheusMetrics"))
|
||||
|
||||
go beeAdminApp.Run()
|
||||
}
|
||||
|
||||
@ -40,7 +40,7 @@ func TestFlashHeader(t *testing.T) {
|
||||
|
||||
// setup the handler
|
||||
handler := NewControllerRegister()
|
||||
handler.Add("/", &TestFlashController{}, "get:TestWriteFlash")
|
||||
handler.Add("/", &TestFlashController{}, SetRouterMethods(&TestFlashController{}, "get:TestWriteFlash"))
|
||||
handler.ServeHTTP(w, r)
|
||||
|
||||
// get the Set-Cookie value
|
||||
|
||||
@ -99,7 +99,7 @@ func (n *Namespace) Filter(action string, filter ...FilterFunc) *Namespace {
|
||||
// Router same as beego.Rourer
|
||||
// refer: https://godoc.org/github.com/beego/beego/v2#Router
|
||||
func (n *Namespace) Router(rootpath string, c ControllerInterface, mappingMethods ...string) *Namespace {
|
||||
n.handlers.Add(rootpath, c, mappingMethods...)
|
||||
n.handlers.Add(rootpath, c, SetRouterMethods(c, mappingMethods...))
|
||||
return n
|
||||
}
|
||||
|
||||
|
||||
@ -118,12 +118,27 @@ type ControllerInfo struct {
|
||||
routerType int
|
||||
initialize func() ControllerInterface
|
||||
methodParams []*param.MethodParam
|
||||
sessionOn bool
|
||||
}
|
||||
|
||||
type ControllerOptions func(*ControllerInfo)
|
||||
|
||||
func (c *ControllerInfo) GetPattern() string {
|
||||
return c.pattern
|
||||
}
|
||||
|
||||
func SetRouterMethods(ctrlInterface ControllerInterface, mappingMethod ...string) ControllerOptions {
|
||||
return func(c *ControllerInfo) {
|
||||
c.methods = parseMappingMethods(ctrlInterface, mappingMethod)
|
||||
}
|
||||
}
|
||||
|
||||
func SetRouterSessionOn(sessionOn bool) ControllerOptions {
|
||||
return func(c *ControllerInfo) {
|
||||
c.sessionOn = sessionOn
|
||||
}
|
||||
}
|
||||
|
||||
// ControllerRegister containers registered router rules, controller handlers and filters.
|
||||
type ControllerRegister struct {
|
||||
routers map[string]*Tree
|
||||
@ -171,40 +186,67 @@ func NewControllerRegisterWithCfg(cfg *Config) *ControllerRegister {
|
||||
// Add("/api/delete",&RestController{},"delete:DeleteFood")
|
||||
// Add("/api",&RestController{},"get,post:ApiFunc"
|
||||
// Add("/simple",&SimpleController{},"get:GetFunc;post:PostFunc")
|
||||
func (p *ControllerRegister) Add(pattern string, c ControllerInterface, mappingMethods ...string) {
|
||||
p.addWithMethodParams(pattern, c, nil, mappingMethods...)
|
||||
func (p *ControllerRegister) Add(pattern string, c ControllerInterface, opts ...ControllerOptions) {
|
||||
p.addWithMethodParams(pattern, c, nil, opts...)
|
||||
}
|
||||
|
||||
func (p *ControllerRegister) addWithMethodParams(pattern string, c ControllerInterface, methodParams []*param.MethodParam, mappingMethods ...string) {
|
||||
func parseMappingMethods(c ControllerInterface, mappingMethods []string) map[string]string {
|
||||
reflectVal := reflect.ValueOf(c)
|
||||
t := reflect.Indirect(reflectVal).Type()
|
||||
methods := make(map[string]string)
|
||||
if len(mappingMethods) > 0 {
|
||||
semi := strings.Split(mappingMethods[0], ";")
|
||||
for _, v := range semi {
|
||||
colon := strings.Split(v, ":")
|
||||
if len(colon) != 2 {
|
||||
panic("method mapping format is invalid")
|
||||
|
||||
if len(mappingMethods) == 0 {
|
||||
return methods
|
||||
}
|
||||
|
||||
semi := strings.Split(mappingMethods[0], ";")
|
||||
for _, v := range semi {
|
||||
colon := strings.Split(v, ":")
|
||||
if len(colon) != 2 {
|
||||
panic("method mapping format is invalid")
|
||||
}
|
||||
comma := strings.Split(colon[0], ",")
|
||||
for _, m := range comma {
|
||||
if m != "*" && !HTTPMETHOD[strings.ToUpper(m)] {
|
||||
panic(v + " is an invalid method mapping. Method doesn't exist " + m)
|
||||
}
|
||||
comma := strings.Split(colon[0], ",")
|
||||
for _, m := range comma {
|
||||
if m == "*" || HTTPMETHOD[strings.ToUpper(m)] {
|
||||
if val := reflectVal.MethodByName(colon[1]); val.IsValid() {
|
||||
methods[strings.ToUpper(m)] = colon[1]
|
||||
} else {
|
||||
panic("'" + colon[1] + "' method doesn't exist in the controller " + t.Name())
|
||||
}
|
||||
} else {
|
||||
panic(v + " is an invalid method mapping. Method doesn't exist " + m)
|
||||
}
|
||||
if val := reflectVal.MethodByName(colon[1]); val.IsValid() {
|
||||
methods[strings.ToUpper(m)] = colon[1]
|
||||
continue
|
||||
}
|
||||
panic("'" + colon[1] + "' method doesn't exist in the controller " + t.Name())
|
||||
}
|
||||
}
|
||||
|
||||
return methods
|
||||
}
|
||||
|
||||
func (p *ControllerRegister) addRouterForMethod(route *ControllerInfo) {
|
||||
if len(route.methods) == 0 {
|
||||
for m := range HTTPMETHOD {
|
||||
p.addToRouter(m, route.pattern, route)
|
||||
}
|
||||
return
|
||||
}
|
||||
for k := range route.methods {
|
||||
if k != "*" {
|
||||
p.addToRouter(k, route.pattern, route)
|
||||
continue
|
||||
}
|
||||
for m := range HTTPMETHOD {
|
||||
p.addToRouter(m, route.pattern, route)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (p *ControllerRegister) addWithMethodParams(pattern string, c ControllerInterface, methodParams []*param.MethodParam, opts ...ControllerOptions) {
|
||||
reflectVal := reflect.ValueOf(c)
|
||||
t := reflect.Indirect(reflectVal).Type()
|
||||
|
||||
route := &ControllerInfo{}
|
||||
route.pattern = pattern
|
||||
route.methods = methods
|
||||
route.routerType = routerTypeBeego
|
||||
route.sessionOn = p.cfg.WebConfig.Session.SessionOn
|
||||
route.controllerType = t
|
||||
route.initialize = func() ControllerInterface {
|
||||
vc := reflect.New(route.controllerType)
|
||||
@ -229,23 +271,18 @@ func (p *ControllerRegister) addWithMethodParams(pattern string, c ControllerInt
|
||||
|
||||
return execController
|
||||
}
|
||||
|
||||
route.methodParams = methodParams
|
||||
if len(methods) == 0 {
|
||||
for m := range HTTPMETHOD {
|
||||
p.addToRouter(m, pattern, route)
|
||||
}
|
||||
} else {
|
||||
for k := range methods {
|
||||
if k == "*" {
|
||||
for m := range HTTPMETHOD {
|
||||
p.addToRouter(m, pattern, route)
|
||||
}
|
||||
} else {
|
||||
p.addToRouter(k, pattern, route)
|
||||
}
|
||||
}
|
||||
for i := range opts {
|
||||
opts[i](route)
|
||||
}
|
||||
|
||||
globalSessionOn := p.cfg.WebConfig.Session.SessionOn
|
||||
if !globalSessionOn && route.sessionOn {
|
||||
logs.Warn("global sessionOn is false, sessionOn of router [%s] can't be set to true", route.pattern)
|
||||
route.sessionOn = globalSessionOn
|
||||
}
|
||||
|
||||
p.addRouterForMethod(route)
|
||||
}
|
||||
|
||||
func (p *ControllerRegister) addToRouter(method, pattern string, r *ControllerInfo) {
|
||||
@ -273,7 +310,8 @@ func (p *ControllerRegister) Include(cList ...ControllerInterface) {
|
||||
for _, f := range a.Filters {
|
||||
p.InsertFilter(f.Pattern, f.Pos, f.Filter, WithReturnOnOutput(f.ReturnOnOutput), WithResetParams(f.ResetParams))
|
||||
}
|
||||
p.addWithMethodParams(a.Router, c, a.MethodParams, strings.Join(a.AllowHTTPMethods, ",")+":"+a.Method)
|
||||
|
||||
p.addWithMethodParams(a.Router, c, a.MethodParams, SetRouterMethods(c, strings.Join(a.AllowHTTPMethods, ",")+":"+a.Method))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -379,6 +417,7 @@ func (p *ControllerRegister) AddMethod(method, pattern string, f FilterFunc) {
|
||||
route := &ControllerInfo{}
|
||||
route.pattern = pattern
|
||||
route.routerType = routerTypeRESTFul
|
||||
route.sessionOn = p.cfg.WebConfig.Session.SessionOn
|
||||
route.runFunction = f
|
||||
methods := make(map[string]string)
|
||||
if method == "*" {
|
||||
@ -399,6 +438,7 @@ func (p *ControllerRegister) Handler(pattern string, h http.Handler, options ...
|
||||
route := &ControllerInfo{}
|
||||
route.pattern = pattern
|
||||
route.routerType = routerTypeHandler
|
||||
route.sessionOn = p.cfg.WebConfig.Session.SessionOn
|
||||
route.handler = h
|
||||
if len(options) > 0 {
|
||||
if _, ok := options[0].(bool); ok {
|
||||
@ -433,6 +473,7 @@ func (p *ControllerRegister) AddAutoPrefix(prefix string, c ControllerInterface)
|
||||
if !utils.InSlice(rt.Method(i).Name, exceptMethod) {
|
||||
route := &ControllerInfo{}
|
||||
route.routerType = routerTypeBeego
|
||||
route.sessionOn = p.cfg.WebConfig.Session.SessionOn
|
||||
route.methods = map[string]string{"*": rt.Method(i).Name}
|
||||
route.controllerType = ct
|
||||
pattern := path.Join(prefix, strings.ToLower(controllerName), strings.ToLower(rt.Method(i).Name), "*")
|
||||
@ -542,7 +583,7 @@ func (p *ControllerRegister) getURL(t *Tree, url, controllerName, methodName str
|
||||
for _, l := range t.leaves {
|
||||
if c, ok := l.runObject.(*ControllerInfo); ok {
|
||||
if c.routerType == routerTypeBeego &&
|
||||
strings.HasSuffix(path.Join(c.controllerType.PkgPath(), c.controllerType.Name()), controllerName) {
|
||||
strings.HasSuffix(path.Join(c.controllerType.PkgPath(), c.controllerType.Name()), `/`+controllerName) {
|
||||
find := false
|
||||
if HTTPMETHOD[strings.ToUpper(methodName)] {
|
||||
if len(c.methods) == 0 {
|
||||
@ -664,12 +705,15 @@ func (p *ControllerRegister) serveHttp(ctx *beecontext.Context) {
|
||||
r := ctx.Request
|
||||
rw := ctx.ResponseWriter.ResponseWriter
|
||||
var (
|
||||
runRouter reflect.Type
|
||||
findRouter bool
|
||||
runMethod string
|
||||
methodParams []*param.MethodParam
|
||||
routerInfo *ControllerInfo
|
||||
isRunnable bool
|
||||
runRouter reflect.Type
|
||||
findRouter bool
|
||||
runMethod string
|
||||
methodParams []*param.MethodParam
|
||||
routerInfo *ControllerInfo
|
||||
isRunnable bool
|
||||
currentSessionOn bool
|
||||
originRouterInfo *ControllerInfo
|
||||
originFindRouter bool
|
||||
)
|
||||
|
||||
if p.cfg.RecoverFunc != nil {
|
||||
@ -735,7 +779,12 @@ func (p *ControllerRegister) serveHttp(ctx *beecontext.Context) {
|
||||
}
|
||||
|
||||
// session init
|
||||
if p.cfg.WebConfig.Session.SessionOn {
|
||||
currentSessionOn = p.cfg.WebConfig.Session.SessionOn
|
||||
originRouterInfo, originFindRouter = p.FindRouter(ctx)
|
||||
if originFindRouter {
|
||||
currentSessionOn = originRouterInfo.sessionOn
|
||||
}
|
||||
if currentSessionOn {
|
||||
ctx.Input.CruSession, err = GlobalSessions.SessionStart(rw, r)
|
||||
if err != nil {
|
||||
logs.Error(err)
|
||||
|
||||
@ -26,6 +26,14 @@ import (
|
||||
"github.com/beego/beego/v2/server/web/context"
|
||||
)
|
||||
|
||||
type PrefixTestController struct {
|
||||
Controller
|
||||
}
|
||||
|
||||
func (ptc *PrefixTestController) PrefixList() {
|
||||
ptc.Ctx.Output.Body([]byte("i am list in prefix test"))
|
||||
}
|
||||
|
||||
type TestController struct {
|
||||
Controller
|
||||
}
|
||||
@ -87,10 +95,24 @@ func (jc *JSONController) Get() {
|
||||
jc.Ctx.Output.Body([]byte("ok"))
|
||||
}
|
||||
|
||||
func TestPrefixUrlFor(t *testing.T){
|
||||
handler := NewControllerRegister()
|
||||
handler.Add("/my/prefix/list", &PrefixTestController{}, "get:PrefixList")
|
||||
|
||||
if a := handler.URLFor(`PrefixTestController.PrefixList`); a != `/my/prefix/list` {
|
||||
logs.Info(a)
|
||||
t.Errorf("PrefixTestController.PrefixList must equal to /my/prefix/list")
|
||||
}
|
||||
if a := handler.URLFor(`TestController.PrefixList`); a != `` {
|
||||
logs.Info(a)
|
||||
t.Errorf("TestController.PrefixList must equal to empty string")
|
||||
}
|
||||
}
|
||||
|
||||
func TestUrlFor(t *testing.T) {
|
||||
handler := NewControllerRegister()
|
||||
handler.Add("/api/list", &TestController{}, "*:List")
|
||||
handler.Add("/person/:last/:first", &TestController{}, "*:Param")
|
||||
handler.Add("/api/list", &TestController{}, SetRouterMethods(&TestController{}, "*:List"))
|
||||
handler.Add("/person/:last/:first", &TestController{}, SetRouterMethods(&TestController{}, "*:Param"))
|
||||
if a := handler.URLFor("TestController.List"); a != "/api/list" {
|
||||
logs.Info(a)
|
||||
t.Errorf("TestController.List must equal to /api/list")
|
||||
@ -113,9 +135,9 @@ func TestUrlFor3(t *testing.T) {
|
||||
|
||||
func TestUrlFor2(t *testing.T) {
|
||||
handler := NewControllerRegister()
|
||||
handler.Add("/v1/:v/cms_:id(.+)_:page(.+).html", &TestController{}, "*:List")
|
||||
handler.Add("/v1/:username/edit", &TestController{}, "get:GetURL")
|
||||
handler.Add("/v1/:v(.+)_cms/ttt_:id(.+)_:page(.+).html", &TestController{}, "*:Param")
|
||||
handler.Add("/v1/:v/cms_:id(.+)_:page(.+).html", &TestController{}, SetRouterMethods(&TestController{}, "*:List"))
|
||||
handler.Add("/v1/:username/edit", &TestController{}, SetRouterMethods(&TestController{}, "get:GetURL"))
|
||||
handler.Add("/v1/:v(.+)_cms/ttt_:id(.+)_:page(.+).html", &TestController{}, SetRouterMethods(&TestController{}, "*:Param"))
|
||||
handler.Add("/:year:int/:month:int/:title/:entid", &TestController{})
|
||||
if handler.URLFor("TestController.GetURL", ":username", "astaxie") != "/v1/astaxie/edit" {
|
||||
logs.Info(handler.URLFor("TestController.GetURL"))
|
||||
@ -145,7 +167,7 @@ func TestUserFunc(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
handler := NewControllerRegister()
|
||||
handler.Add("/api/list", &TestController{}, "*:List")
|
||||
handler.Add("/api/list", &TestController{}, SetRouterMethods(&TestController{}, "*:List"))
|
||||
handler.ServeHTTP(w, r)
|
||||
if w.Body.String() != "i am list" {
|
||||
t.Errorf("user define func can't run")
|
||||
@ -235,7 +257,7 @@ func TestRouteOk(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
handler := NewControllerRegister()
|
||||
handler.Add("/person/:last/:first", &TestController{}, "get:GetParams")
|
||||
handler.Add("/person/:last/:first", &TestController{}, SetRouterMethods(&TestController{}, "get:GetParams"))
|
||||
handler.ServeHTTP(w, r)
|
||||
body := w.Body.String()
|
||||
if body != "anderson+thomas+kungfu" {
|
||||
@ -249,7 +271,7 @@ func TestManyRoute(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
handler := NewControllerRegister()
|
||||
handler.Add("/beego:id([0-9]+)-:page([0-9]+).html", &TestController{}, "get:GetManyRouter")
|
||||
handler.Add("/beego:id([0-9]+)-:page([0-9]+).html", &TestController{}, SetRouterMethods(&TestController{}, "get:GetManyRouter"))
|
||||
handler.ServeHTTP(w, r)
|
||||
|
||||
body := w.Body.String()
|
||||
@ -266,7 +288,7 @@ func TestEmptyResponse(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
handler := NewControllerRegister()
|
||||
handler.Add("/beego-empty.html", &TestController{}, "get:GetEmptyBody")
|
||||
handler.Add("/beego-empty.html", &TestController{}, SetRouterMethods(&TestController{}, "get:GetEmptyBody"))
|
||||
handler.ServeHTTP(w, r)
|
||||
|
||||
if body := w.Body.String(); body != "" {
|
||||
@ -750,3 +772,59 @@ func TestRouterEntityTooLargeCopyBody(t *testing.T) {
|
||||
t.Errorf("TestRouterRequestEntityTooLarge can't run")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRouterSessionSet(t *testing.T) {
|
||||
oldGlobalSessionOn := BConfig.WebConfig.Session.SessionOn
|
||||
defer func() {
|
||||
BConfig.WebConfig.Session.SessionOn = oldGlobalSessionOn
|
||||
}()
|
||||
|
||||
// global sessionOn = false, router sessionOn = false
|
||||
r, _ := http.NewRequest("GET", "/user", nil)
|
||||
w := httptest.NewRecorder()
|
||||
handler := NewControllerRegister()
|
||||
handler.Add("/user", &TestController{}, SetRouterMethods(&TestController{}, "get:Get"),
|
||||
SetRouterSessionOn(false))
|
||||
handler.ServeHTTP(w, r)
|
||||
if w.Header().Get("Set-Cookie") != "" {
|
||||
t.Errorf("TestRotuerSessionSet failed")
|
||||
}
|
||||
|
||||
// global sessionOn = false, router sessionOn = true
|
||||
r, _ = http.NewRequest("GET", "/user", nil)
|
||||
w = httptest.NewRecorder()
|
||||
handler = NewControllerRegister()
|
||||
handler.Add("/user", &TestController{}, SetRouterMethods(&TestController{}, "get:Get"),
|
||||
SetRouterSessionOn(true))
|
||||
handler.ServeHTTP(w, r)
|
||||
if w.Header().Get("Set-Cookie") != "" {
|
||||
t.Errorf("TestRotuerSessionSet failed")
|
||||
}
|
||||
|
||||
BConfig.WebConfig.Session.SessionOn = true
|
||||
if err := registerSession(); err != nil {
|
||||
t.Errorf("register session failed, error: %s", err.Error())
|
||||
}
|
||||
// global sessionOn = true, router sessionOn = false
|
||||
r, _ = http.NewRequest("GET", "/user", nil)
|
||||
w = httptest.NewRecorder()
|
||||
handler = NewControllerRegister()
|
||||
handler.Add("/user", &TestController{}, SetRouterMethods(&TestController{}, "get:Get"),
|
||||
SetRouterSessionOn(false))
|
||||
handler.ServeHTTP(w, r)
|
||||
if w.Header().Get("Set-Cookie") != "" {
|
||||
t.Errorf("TestRotuerSessionSet failed")
|
||||
}
|
||||
|
||||
// global sessionOn = true, router sessionOn = true
|
||||
r, _ = http.NewRequest("GET", "/user", nil)
|
||||
w = httptest.NewRecorder()
|
||||
handler = NewControllerRegister()
|
||||
handler.Add("/user", &TestController{}, SetRouterMethods(&TestController{}, "get:Get"),
|
||||
SetRouterSessionOn(true))
|
||||
handler.ServeHTTP(w, r)
|
||||
if w.Header().Get("Set-Cookie") == "" {
|
||||
t.Errorf("TestRotuerSessionSet failed")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -266,8 +266,8 @@ func (app *HttpServer) Run(addr string, mws ...MiddleWare) {
|
||||
}
|
||||
|
||||
// Router see HttpServer.Router
|
||||
func Router(rootpath string, c ControllerInterface, mappingMethods ...string) *HttpServer {
|
||||
return BeeApp.Router(rootpath, c, mappingMethods...)
|
||||
func Router(rootpath string, c ControllerInterface, opts ...ControllerOptions) *HttpServer {
|
||||
return BeeApp.Router(rootpath, c, opts...)
|
||||
}
|
||||
|
||||
// Router adds a patterned controller handler to BeeApp.
|
||||
@ -286,8 +286,8 @@ func Router(rootpath string, c ControllerInterface, mappingMethods ...string) *H
|
||||
// beego.Router("/api/create",&RestController{},"post:CreateFood")
|
||||
// beego.Router("/api/update",&RestController{},"put:UpdateFood")
|
||||
// beego.Router("/api/delete",&RestController{},"delete:DeleteFood")
|
||||
func (app *HttpServer) Router(rootPath string, c ControllerInterface, mappingMethods ...string) *HttpServer {
|
||||
app.Handlers.Add(rootPath, c, mappingMethods...)
|
||||
func (app *HttpServer) Router(rootPath string, c ControllerInterface, opts ...ControllerOptions) *HttpServer {
|
||||
app.Handlers.Add(rootPath, c, opts...)
|
||||
return app
|
||||
}
|
||||
|
||||
|
||||
@ -210,9 +210,9 @@ func (t *Tree) AddRouter(pattern string, runObject interface{}) {
|
||||
func (t *Tree) addseg(segments []string, route interface{}, wildcards []string, reg string) {
|
||||
if len(segments) == 0 {
|
||||
if reg != "" {
|
||||
t.leaves = append(t.leaves, &leafInfo{runObject: route, wildcards: wildcards, regexps: regexp.MustCompile("^" + reg + "$")})
|
||||
t.leaves = append([]*leafInfo{{runObject: route, wildcards: wildcards, regexps: regexp.MustCompile("^" + reg + "$")}}, t.leaves...)
|
||||
} else {
|
||||
t.leaves = append(t.leaves, &leafInfo{runObject: route, wildcards: wildcards})
|
||||
t.leaves = append([]*leafInfo{{runObject: route, wildcards: wildcards}}, t.leaves...)
|
||||
}
|
||||
} else {
|
||||
seg := segments[0]
|
||||
|
||||
@ -90,7 +90,17 @@ func init() {
|
||||
routers = append(routers, matchTestInfo("/v1/:v(.+)_cms/ttt_:id(.+)_:page(.+).html", "/v1/2_cms/ttt_123_1.html", map[string]string{":v": "2", ":id": "123", ":page": "1"}))
|
||||
routers = append(routers, matchTestInfo("/api/projects/:pid/members/?:mid", "/api/projects/1/members", map[string]string{":pid": "1"}))
|
||||
routers = append(routers, matchTestInfo("/api/projects/:pid/members/?:mid", "/api/projects/1/members/2", map[string]string{":pid": "1", ":mid": "2"}))
|
||||
|
||||
routers = append(routers, matchTestInfo("/?:year/?:month/?:day", "/2020/11/10", map[string]string{":year": "2020", ":month": "11", ":day": "10"}))
|
||||
routers = append(routers, matchTestInfo("/?:year/?:month/?:day", "/2020/11", map[string]string{":year": "2020", ":month": "11"}))
|
||||
routers = append(routers, matchTestInfo("/?:year", "/2020", map[string]string{":year": "2020"}))
|
||||
routers = append(routers, matchTestInfo("/?:year([0-9]+)/?:month([0-9]+)/mid/?:day([0-9]+)/?:hour([0-9]+)", "/2020/11/mid/10/24", map[string]string{":year": "2020", ":month": "11", ":day": "10", ":hour": "24"}))
|
||||
routers = append(routers, matchTestInfo("/?:year/?:month/mid/?:day/?:hour", "/2020/mid/10", map[string]string{":year": "2020", ":day": "10"}))
|
||||
routers = append(routers, matchTestInfo("/?:year/?:month/mid/?:day/?:hour", "/2020/11/mid", map[string]string{":year": "2020", ":month": "11"}))
|
||||
routers = append(routers, matchTestInfo("/?:year/?:month/mid/?:day/?:hour", "/mid/10/24", map[string]string{":day": "10", ":hour": "24"}))
|
||||
routers = append(routers, matchTestInfo("/?:year([0-9]+)/:month([0-9]+)/mid/:day([0-9]+)/?:hour([0-9]+)", "/2020/11/mid/10/24", map[string]string{":year": "2020", ":month": "11", ":day": "10", ":hour": "24"}))
|
||||
routers = append(routers, matchTestInfo("/?:year/:month/mid/:day/?:hour", "/11/mid/10/24", map[string]string{":month": "11", ":day": "10"}))
|
||||
routers = append(routers, matchTestInfo("/?:year/:month/mid/:day/?:hour", "/2020/11/mid/10", map[string]string{":year": "2020", ":month": "11", ":day": "10"}))
|
||||
routers = append(routers, matchTestInfo("/?:year/:month/mid/:day/?:hour", "/11/mid/10", map[string]string{":month": "11", ":day": "10"}))
|
||||
// not match example
|
||||
|
||||
// https://github.com/beego/beego/v2/issues/3865
|
||||
|
||||
@ -75,9 +75,9 @@ func TestUnregisterFixedRouteRoot(t *testing.T) {
|
||||
var method = "GET"
|
||||
|
||||
handler := NewControllerRegister()
|
||||
handler.Add("/", &TestPreUnregController{}, "get:GetFixedRoot")
|
||||
handler.Add("/level1", &TestPreUnregController{}, "get:GetFixedLevel1")
|
||||
handler.Add("/level1/level2", &TestPreUnregController{}, "get:GetFixedLevel2")
|
||||
handler.Add("/", &TestPreUnregController{}, SetRouterMethods(&TestPreUnregController{}, "get:GetFixedRoot"))
|
||||
handler.Add("/level1", &TestPreUnregController{}, SetRouterMethods(&TestPreUnregController{}, "get:GetFixedLevel1"))
|
||||
handler.Add("/level1/level2", &TestPreUnregController{}, SetRouterMethods(&TestPreUnregController{}, "get:GetFixedLevel2"))
|
||||
|
||||
// Test original root
|
||||
testHelperFnContentCheck(t, handler, "Test original root",
|
||||
@ -96,7 +96,7 @@ func TestUnregisterFixedRouteRoot(t *testing.T) {
|
||||
|
||||
// Replace the root path TestPreUnregController action with the action from
|
||||
// TestPostUnregController
|
||||
handler.Add("/", &TestPostUnregController{}, "get:GetFixedRoot")
|
||||
handler.Add("/", &TestPostUnregController{}, SetRouterMethods(&TestPostUnregController{}, "get:GetFixedRoot"))
|
||||
|
||||
// Test replacement root (expect change)
|
||||
testHelperFnContentCheck(t, handler, "Test replacement root (expect change)", method, "/", contentRootReplacement)
|
||||
@ -117,9 +117,9 @@ func TestUnregisterFixedRouteLevel1(t *testing.T) {
|
||||
var method = "GET"
|
||||
|
||||
handler := NewControllerRegister()
|
||||
handler.Add("/", &TestPreUnregController{}, "get:GetFixedRoot")
|
||||
handler.Add("/level1", &TestPreUnregController{}, "get:GetFixedLevel1")
|
||||
handler.Add("/level1/level2", &TestPreUnregController{}, "get:GetFixedLevel2")
|
||||
handler.Add("/", &TestPreUnregController{}, SetRouterMethods(&TestPreUnregController{}, "get:GetFixedRoot"))
|
||||
handler.Add("/level1", &TestPreUnregController{}, SetRouterMethods(&TestPreUnregController{}, "get:GetFixedLevel1"))
|
||||
handler.Add("/level1/level2", &TestPreUnregController{}, SetRouterMethods(&TestPreUnregController{}, "get:GetFixedLevel2"))
|
||||
|
||||
// Test original root
|
||||
testHelperFnContentCheck(t, handler,
|
||||
@ -146,7 +146,7 @@ func TestUnregisterFixedRouteLevel1(t *testing.T) {
|
||||
|
||||
// Replace the "level1" path TestPreUnregController action with the action from
|
||||
// TestPostUnregController
|
||||
handler.Add("/level1", &TestPostUnregController{}, "get:GetFixedLevel1")
|
||||
handler.Add("/level1", &TestPostUnregController{}, SetRouterMethods(&TestPostUnregController{}, "get:GetFixedLevel1"))
|
||||
|
||||
// Test replacement root (expect no change from the original)
|
||||
testHelperFnContentCheck(t, handler, "Test replacement root (expect no change from the original)", method, "/", contentRootOriginal)
|
||||
@ -167,9 +167,9 @@ func TestUnregisterFixedRouteLevel2(t *testing.T) {
|
||||
var method = "GET"
|
||||
|
||||
handler := NewControllerRegister()
|
||||
handler.Add("/", &TestPreUnregController{}, "get:GetFixedRoot")
|
||||
handler.Add("/level1", &TestPreUnregController{}, "get:GetFixedLevel1")
|
||||
handler.Add("/level1/level2", &TestPreUnregController{}, "get:GetFixedLevel2")
|
||||
handler.Add("/", &TestPreUnregController{}, SetRouterMethods(&TestPreUnregController{}, "get:GetFixedRoot"))
|
||||
handler.Add("/level1", &TestPreUnregController{}, SetRouterMethods(&TestPreUnregController{}, "get:GetFixedLevel1"))
|
||||
handler.Add("/level1/level2", &TestPreUnregController{}, SetRouterMethods(&TestPreUnregController{}, "get:GetFixedLevel2"))
|
||||
|
||||
// Test original root
|
||||
testHelperFnContentCheck(t, handler,
|
||||
@ -196,7 +196,7 @@ func TestUnregisterFixedRouteLevel2(t *testing.T) {
|
||||
|
||||
// Replace the "/level1/level2" path TestPreUnregController action with the action from
|
||||
// TestPostUnregController
|
||||
handler.Add("/level1/level2", &TestPostUnregController{}, "get:GetFixedLevel2")
|
||||
handler.Add("/level1/level2", &TestPostUnregController{}, SetRouterMethods(&TestPostUnregController{}, "get:GetFixedLevel2"))
|
||||
|
||||
// Test replacement root (expect no change from the original)
|
||||
testHelperFnContentCheck(t, handler, "Test replacement root (expect no change from the original)", method, "/", contentRootOriginal)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user