mirror of https://github.com/grafana/grafana.git
Security: Fixes for CVE-2025-6197 and CVE-2025-6023 (#108281)
Backend Unit Tests / Grafana (push) Has been cancelled
Details
Backend Unit Tests / Grafana Enterprise (push) Has been cancelled
Details
CodeQL checks / Analyze (go) (push) Has been cancelled
Details
CodeQL checks / Analyze (javascript) (push) Has been cancelled
Details
CodeQL checks / Analyze (python) (push) Has been cancelled
Details
Lint Frontend / Verify i18n (push) Has been cancelled
Details
Lint Frontend / Lint (push) Has been cancelled
Details
Lint Frontend / Typecheck (push) Has been cancelled
Details
Lint Frontend / Betterer (push) Has been cancelled
Details
End-to-end tests / Build & Package Grafana (push) Has been cancelled
Details
Frontend tests / Unit tests (${{ matrix.chunk }} / 8) (1) (push) Has been cancelled
Details
Frontend tests / Unit tests (${{ matrix.chunk }} / 8) (2) (push) Has been cancelled
Details
Frontend tests / Unit tests (${{ matrix.chunk }} / 8) (3) (push) Has been cancelled
Details
Frontend tests / Unit tests (${{ matrix.chunk }} / 8) (4) (push) Has been cancelled
Details
Frontend tests / Unit tests (${{ matrix.chunk }} / 8) (5) (push) Has been cancelled
Details
Frontend tests / Unit tests (${{ matrix.chunk }} / 8) (6) (push) Has been cancelled
Details
Frontend tests / Unit tests (${{ matrix.chunk }} / 8) (7) (push) Has been cancelled
Details
Frontend tests / Unit tests (${{ matrix.chunk }} / 8) (8) (push) Has been cancelled
Details
Integration Tests / Sqlite (push) Has been cancelled
Details
Integration Tests / MySQL (push) Has been cancelled
Details
Integration Tests / Postgres (push) Has been cancelled
Details
Dispatch sync to mirror / dispatch-job (push) Has been cancelled
Details
End-to-end tests / ${{ matrix.suite }} (dashboards-suite) (push) Has been cancelled
Details
End-to-end tests / ${{ matrix.suite }} (panels-suite) (push) Has been cancelled
Details
End-to-end tests / ${{ matrix.suite }} (smoke-tests-suite) (push) Has been cancelled
Details
End-to-end tests / ${{ matrix.suite }} (various-suite) (push) Has been cancelled
Details
End-to-end tests / ${{ matrix.suite }} (old arch) (old-arch/dashboards-suite) (push) Has been cancelled
Details
End-to-end tests / ${{ matrix.suite }} (old arch) (old-arch/panels-suite) (push) Has been cancelled
Details
End-to-end tests / ${{ matrix.suite }} (old arch) (old-arch/smoke-tests-suite) (push) Has been cancelled
Details
End-to-end tests / ${{ matrix.suite }} (old arch) (old-arch/various-suite) (push) Has been cancelled
Details
Backend Unit Tests / Grafana (push) Has been cancelled
Details
Backend Unit Tests / Grafana Enterprise (push) Has been cancelled
Details
CodeQL checks / Analyze (go) (push) Has been cancelled
Details
CodeQL checks / Analyze (javascript) (push) Has been cancelled
Details
CodeQL checks / Analyze (python) (push) Has been cancelled
Details
Lint Frontend / Verify i18n (push) Has been cancelled
Details
Lint Frontend / Lint (push) Has been cancelled
Details
Lint Frontend / Typecheck (push) Has been cancelled
Details
Lint Frontend / Betterer (push) Has been cancelled
Details
End-to-end tests / Build & Package Grafana (push) Has been cancelled
Details
Frontend tests / Unit tests (${{ matrix.chunk }} / 8) (1) (push) Has been cancelled
Details
Frontend tests / Unit tests (${{ matrix.chunk }} / 8) (2) (push) Has been cancelled
Details
Frontend tests / Unit tests (${{ matrix.chunk }} / 8) (3) (push) Has been cancelled
Details
Frontend tests / Unit tests (${{ matrix.chunk }} / 8) (4) (push) Has been cancelled
Details
Frontend tests / Unit tests (${{ matrix.chunk }} / 8) (5) (push) Has been cancelled
Details
Frontend tests / Unit tests (${{ matrix.chunk }} / 8) (6) (push) Has been cancelled
Details
Frontend tests / Unit tests (${{ matrix.chunk }} / 8) (7) (push) Has been cancelled
Details
Frontend tests / Unit tests (${{ matrix.chunk }} / 8) (8) (push) Has been cancelled
Details
Integration Tests / Sqlite (push) Has been cancelled
Details
Integration Tests / MySQL (push) Has been cancelled
Details
Integration Tests / Postgres (push) Has been cancelled
Details
Dispatch sync to mirror / dispatch-job (push) Has been cancelled
Details
End-to-end tests / ${{ matrix.suite }} (dashboards-suite) (push) Has been cancelled
Details
End-to-end tests / ${{ matrix.suite }} (panels-suite) (push) Has been cancelled
Details
End-to-end tests / ${{ matrix.suite }} (smoke-tests-suite) (push) Has been cancelled
Details
End-to-end tests / ${{ matrix.suite }} (various-suite) (push) Has been cancelled
Details
End-to-end tests / ${{ matrix.suite }} (old arch) (old-arch/dashboards-suite) (push) Has been cancelled
Details
End-to-end tests / ${{ matrix.suite }} (old arch) (old-arch/panels-suite) (push) Has been cancelled
Details
End-to-end tests / ${{ matrix.suite }} (old arch) (old-arch/smoke-tests-suite) (push) Has been cancelled
Details
End-to-end tests / ${{ matrix.suite }} (old arch) (old-arch/various-suite) (push) Has been cancelled
Details
fix(redirect): make validation of redirect uri stricter Co-authored-by: volcanonoodle <114113189+volcanonoodle@users.noreply.github.com>
This commit is contained in:
parent
10ff2728a7
commit
0567ef29be
|
@ -7,6 +7,8 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"path"
|
||||||
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/api/response"
|
"github.com/grafana/grafana/pkg/api/response"
|
||||||
|
@ -39,6 +41,9 @@ var getViewIndex = func() string {
|
||||||
return viewIndex
|
return viewIndex
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Only allow redirects that start with an alphanumerical character, a dash or an underscore.
|
||||||
|
var redirectRe = regexp.MustCompile(`^/[a-zA-Z0-9-_].*`)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
errAbsoluteRedirectTo = errors.New("absolute URLs are not allowed for redirect_to cookie value")
|
errAbsoluteRedirectTo = errors.New("absolute URLs are not allowed for redirect_to cookie value")
|
||||||
errInvalidRedirectTo = errors.New("invalid redirect_to cookie value")
|
errInvalidRedirectTo = errors.New("invalid redirect_to cookie value")
|
||||||
|
@ -68,6 +73,15 @@ func (hs *HTTPServer) ValidateRedirectTo(redirectTo string) error {
|
||||||
return errForbiddenRedirectTo
|
return errForbiddenRedirectTo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cleanPath := path.Clean(to.Path)
|
||||||
|
// "." is what path.Clean returns for empty paths
|
||||||
|
if cleanPath == "." {
|
||||||
|
return errForbiddenRedirectTo
|
||||||
|
}
|
||||||
|
if to.Path != "/" && !redirectRe.MatchString(cleanPath) {
|
||||||
|
return errForbiddenRedirectTo
|
||||||
|
}
|
||||||
|
|
||||||
// when using a subUrl, the redirect_to should start with the subUrl (which contains the leading slash), otherwise the redirect
|
// when using a subUrl, the redirect_to should start with the subUrl (which contains the leading slash), otherwise the redirect
|
||||||
// will send the user to the wrong location
|
// will send the user to the wrong location
|
||||||
if hs.Cfg.AppSubURL != "" && !strings.HasPrefix(to.Path, hs.Cfg.AppSubURL+"/") {
|
if hs.Cfg.AppSubURL != "" && !strings.HasPrefix(to.Path, hs.Cfg.AppSubURL+"/") {
|
||||||
|
|
|
@ -14,20 +14,16 @@ import (
|
||||||
"github.com/grafana/grafana/pkg/services/authn/authntest"
|
"github.com/grafana/grafana/pkg/services/authn/authntest"
|
||||||
"github.com/grafana/grafana/pkg/services/secrets/fakes"
|
"github.com/grafana/grafana/pkg/services/secrets/fakes"
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
|
"github.com/grafana/grafana/pkg/web/webtest"
|
||||||
)
|
)
|
||||||
|
|
||||||
func setClientWithoutRedirectFollow(t *testing.T) {
|
func setClientWithoutRedirectFollow(t *testing.T, s *webtest.Server) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
old := http.DefaultClient
|
s.HttpClient = &http.Client{
|
||||||
http.DefaultClient = &http.Client{
|
|
||||||
CheckRedirect: func(req *http.Request, via []*http.Request) error {
|
CheckRedirect: func(req *http.Request, via []*http.Request) error {
|
||||||
return http.ErrUseLastResponse
|
return http.ErrUseLastResponse
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Cleanup(func() {
|
|
||||||
http.DefaultClient = old
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestOAuthLogin_Redirect(t *testing.T) {
|
func TestOAuthLogin_Redirect(t *testing.T) {
|
||||||
|
@ -79,7 +75,7 @@ func TestOAuthLogin_Redirect(t *testing.T) {
|
||||||
})
|
})
|
||||||
|
|
||||||
// we need to prevent the http.Client from following redirects
|
// we need to prevent the http.Client from following redirects
|
||||||
setClientWithoutRedirectFollow(t)
|
setClientWithoutRedirectFollow(t, server)
|
||||||
|
|
||||||
res, err := server.Send(server.NewGetRequest("/login/generic_oauth"))
|
res, err := server.Send(server.NewGetRequest("/login/generic_oauth"))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -155,7 +151,7 @@ func TestOAuthLogin_AuthorizationCode(t *testing.T) {
|
||||||
})
|
})
|
||||||
|
|
||||||
// we need to prevent the http.Client from following redirects
|
// we need to prevent the http.Client from following redirects
|
||||||
setClientWithoutRedirectFollow(t)
|
setClientWithoutRedirectFollow(t, server)
|
||||||
|
|
||||||
res, err := server.Send(server.NewGetRequest("/login/generic_oauth?code=code"))
|
res, err := server.Send(server.NewGetRequest("/login/generic_oauth?code=code"))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -199,7 +195,7 @@ func TestOAuthLogin_Error(t *testing.T) {
|
||||||
hs.SecretsService = fakes.NewFakeSecretsService()
|
hs.SecretsService = fakes.NewFakeSecretsService()
|
||||||
})
|
})
|
||||||
|
|
||||||
setClientWithoutRedirectFollow(t)
|
setClientWithoutRedirectFollow(t, server)
|
||||||
|
|
||||||
res, err := server.Send(server.NewGetRequest("/login/azuread?error=someerror"))
|
res, err := server.Send(server.NewGetRequest("/login/azuread?error=someerror"))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -20,6 +21,7 @@ import (
|
||||||
"github.com/grafana/grafana/pkg/services/user"
|
"github.com/grafana/grafana/pkg/services/user"
|
||||||
"github.com/grafana/grafana/pkg/services/user/usertest"
|
"github.com/grafana/grafana/pkg/services/user/usertest"
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
|
"github.com/grafana/grafana/pkg/web/webtest"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestUserTokenAPIEndpoint(t *testing.T) {
|
func TestUserTokenAPIEndpoint(t *testing.T) {
|
||||||
|
@ -150,6 +152,95 @@ func TestUserTokenAPIEndpoint(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestHTTPServer_RotateUserAuthTokenRedirect(t *testing.T) {
|
||||||
|
redirectTestCases := []struct {
|
||||||
|
name string
|
||||||
|
redirectUrl string
|
||||||
|
expectedUrl string
|
||||||
|
}{
|
||||||
|
// Valid redirects should be preserved
|
||||||
|
{"valid root path", "/", "/"},
|
||||||
|
{"valid simple path", "/hello", "/hello"},
|
||||||
|
{"valid single char path", "/a", "/a"},
|
||||||
|
{"valid nested path", "/asd/hello", "/asd/hello"},
|
||||||
|
|
||||||
|
// Invalid redirects should be converted to root
|
||||||
|
{"backslash domain", `/\grafana.com`, "/"},
|
||||||
|
{"traversal backslash domain", `/a/../\grafana.com`, "/"},
|
||||||
|
{"double slash", "//grafana", "/"},
|
||||||
|
{"missing initial slash", "missingInitialSlash", "/"},
|
||||||
|
{"parent directory", "/../", "/"},
|
||||||
|
}
|
||||||
|
|
||||||
|
sessionTestCases := []struct {
|
||||||
|
name string
|
||||||
|
useSessionStorageRedirect bool
|
||||||
|
}{
|
||||||
|
{"when useSessionStorageRedirect is enabled", true},
|
||||||
|
{"when useSessionStorageRedirect is disabled", false},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, sessionCase := range sessionTestCases {
|
||||||
|
t.Run(sessionCase.name, func(t *testing.T) {
|
||||||
|
for _, redirectCase := range redirectTestCases {
|
||||||
|
t.Run(redirectCase.name, func(t *testing.T) {
|
||||||
|
server := SetupAPITestServer(t, func(hs *HTTPServer) {
|
||||||
|
cfg := setting.NewCfg()
|
||||||
|
cfg.LoginCookieName = "grafana_session"
|
||||||
|
cfg.LoginMaxLifetime = 10 * time.Hour
|
||||||
|
hs.Cfg = cfg
|
||||||
|
hs.log = log.New()
|
||||||
|
hs.AuthTokenService = &authtest.FakeUserAuthTokenService{
|
||||||
|
RotateTokenProvider: func(ctx context.Context, cmd auth.RotateCommand) (*auth.UserToken, error) {
|
||||||
|
return &auth.UserToken{UnhashedToken: "new"}, nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
redirectToQuery := url.QueryEscape(redirectCase.redirectUrl)
|
||||||
|
urlString := "/user/auth-tokens/rotate"
|
||||||
|
|
||||||
|
if sessionCase.useSessionStorageRedirect {
|
||||||
|
urlString = urlString + "?redirectTo=" + redirectToQuery
|
||||||
|
}
|
||||||
|
|
||||||
|
req := server.NewGetRequest(urlString)
|
||||||
|
req.AddCookie(&http.Cookie{Name: "grafana_session", Value: "123", Path: "/"})
|
||||||
|
|
||||||
|
if sessionCase.useSessionStorageRedirect {
|
||||||
|
req = webtest.RequestWithWebContext(req, &contextmodel.ReqContext{UseSessionStorageRedirect: true})
|
||||||
|
} else {
|
||||||
|
req.AddCookie(&http.Cookie{Name: "redirect_to", Value: redirectToQuery, Path: "/"})
|
||||||
|
}
|
||||||
|
|
||||||
|
var redirectStatusCode int
|
||||||
|
var redirectLocation string
|
||||||
|
|
||||||
|
server.HttpClient.CheckRedirect = func(req *http.Request, via []*http.Request) error {
|
||||||
|
if len(via) > 1 {
|
||||||
|
// Stop after first redirect
|
||||||
|
return http.ErrUseLastResponse
|
||||||
|
}
|
||||||
|
|
||||||
|
if req.Response == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
redirectStatusCode = req.Response.StatusCode
|
||||||
|
redirectLocation = req.Response.Header.Get("Location")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
res, err := server.Send(req)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, 302, redirectStatusCode)
|
||||||
|
assert.Equal(t, redirectCase.expectedUrl, redirectLocation)
|
||||||
|
|
||||||
|
require.NoError(t, res.Body.Close())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestHTTPServer_RotateUserAuthToken(t *testing.T) {
|
func TestHTTPServer_RotateUserAuthToken(t *testing.T) {
|
||||||
type testCase struct {
|
type testCase struct {
|
||||||
desc string
|
desc string
|
||||||
|
|
|
@ -3,6 +3,8 @@ package middleware
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"path"
|
||||||
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/services/contexthandler"
|
"github.com/grafana/grafana/pkg/services/contexthandler"
|
||||||
|
@ -11,6 +13,9 @@ import (
|
||||||
"github.com/grafana/grafana/pkg/web"
|
"github.com/grafana/grafana/pkg/web"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Only allow redirects that start with an alphanumerical character, a dash or an underscore.
|
||||||
|
var redirectRe = regexp.MustCompile(`^/?[a-zA-Z0-9-_].*`)
|
||||||
|
|
||||||
// OrgRedirect changes org and redirects users if the
|
// OrgRedirect changes org and redirects users if the
|
||||||
// querystring `orgId` doesn't match the active org.
|
// querystring `orgId` doesn't match the active org.
|
||||||
func OrgRedirect(cfg *setting.Cfg, userSvc user.Service) web.Handler {
|
func OrgRedirect(cfg *setting.Cfg, userSvc user.Service) web.Handler {
|
||||||
|
@ -31,6 +36,11 @@ func OrgRedirect(cfg *setting.Cfg, userSvc user.Service) web.Handler {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !validRedirectPath(c.Req.URL.Path) {
|
||||||
|
// Do not switch orgs or perform the redirect because the new path is not valid
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if err := userSvc.Update(ctx.Req.Context(), &user.UpdateUserCommand{UserID: ctx.UserID, OrgID: &orgId}); err != nil {
|
if err := userSvc.Update(ctx.Req.Context(), &user.UpdateUserCommand{UserID: ctx.UserID, OrgID: &orgId}); err != nil {
|
||||||
if ctx.IsApiRequest() {
|
if ctx.IsApiRequest() {
|
||||||
ctx.JsonApiErr(404, "Not found", nil)
|
ctx.JsonApiErr(404, "Not found", nil)
|
||||||
|
@ -54,3 +64,8 @@ func OrgRedirect(cfg *setting.Cfg, userSvc user.Service) web.Handler {
|
||||||
c.Redirect(newURL, 302)
|
c.Redirect(newURL, 302)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func validRedirectPath(p string) bool {
|
||||||
|
cleanPath := path.Clean(p)
|
||||||
|
return cleanPath == "." || cleanPath == "/" || redirectRe.MatchString(cleanPath)
|
||||||
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package middleware
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net/url"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
@ -23,6 +24,12 @@ func TestOrgRedirectMiddleware(t *testing.T) {
|
||||||
expStatus: 302,
|
expStatus: 302,
|
||||||
expLocation: "/?orgId=3",
|
expLocation: "/?orgId=3",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
desc: "when setting a correct org for the user with an empty path",
|
||||||
|
input: "?orgId=3",
|
||||||
|
expStatus: 302,
|
||||||
|
expLocation: "/?orgId=3",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
desc: "when setting a correct org for the user with '&kiosk'",
|
desc: "when setting a correct org for the user with '&kiosk'",
|
||||||
input: "/?orgId=3&kiosk",
|
input: "/?orgId=3&kiosk",
|
||||||
|
@ -64,6 +71,16 @@ func TestOrgRedirectMiddleware(t *testing.T) {
|
||||||
require.Equal(t, 404, sc.resp.Code)
|
require.Equal(t, 404, sc.resp.Code)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
middlewareScenario(t, "when redirecting to an invalid path", func(t *testing.T, sc *scenarioContext) {
|
||||||
|
sc.withIdentity(&authn.Identity{})
|
||||||
|
|
||||||
|
path := url.QueryEscape(`/\example.com`)
|
||||||
|
sc.m.Get(url.QueryEscape(path), sc.defaultHandler)
|
||||||
|
sc.fakeReq("GET", fmt.Sprintf("%s?orgId=3", path)).exec()
|
||||||
|
|
||||||
|
require.Equal(t, 404, sc.resp.Code)
|
||||||
|
})
|
||||||
|
|
||||||
middlewareScenario(t, "works correctly when grafana is served under a subpath", func(t *testing.T, sc *scenarioContext) {
|
middlewareScenario(t, "works correctly when grafana is served under a subpath", func(t *testing.T, sc *scenarioContext) {
|
||||||
sc.withIdentity(&authn.Identity{})
|
sc.withIdentity(&authn.Identity{})
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@ type Server struct {
|
||||||
Mux *web.Mux
|
Mux *web.Mux
|
||||||
RouteRegister routing.RouteRegister
|
RouteRegister routing.RouteRegister
|
||||||
TestServer *httptest.Server
|
TestServer *httptest.Server
|
||||||
|
HttpClient *http.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewServer starts and returns a new server.
|
// NewServer starts and returns a new server.
|
||||||
|
@ -50,6 +51,7 @@ func NewServer(t testing.TB, routeRegister routing.RouteRegister) *Server {
|
||||||
RouteRegister: routeRegister,
|
RouteRegister: routeRegister,
|
||||||
Mux: m,
|
Mux: m,
|
||||||
TestServer: testServer,
|
TestServer: testServer,
|
||||||
|
HttpClient: &http.Client{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,7 +83,7 @@ func (s *Server) NewRequest(method string, target string, body io.Reader) *http.
|
||||||
|
|
||||||
// Send sends a HTTP request to the test server and returns an HTTP response.
|
// Send sends a HTTP request to the test server and returns an HTTP response.
|
||||||
func (s *Server) Send(req *http.Request) (*http.Response, error) {
|
func (s *Server) Send(req *http.Request) (*http.Response, error) {
|
||||||
return http.DefaultClient.Do(req)
|
return s.HttpClient.Do(req)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SendJSON sets the Content-Type header to application/json and sends
|
// SendJSON sets the Content-Type header to application/json and sends
|
||||||
|
@ -144,6 +146,7 @@ func requestContextMiddleware() web.Middleware {
|
||||||
c.RequestNonce = ctx.RequestNonce
|
c.RequestNonce = ctx.RequestNonce
|
||||||
c.PerfmonTimer = ctx.PerfmonTimer
|
c.PerfmonTimer = ctx.PerfmonTimer
|
||||||
c.LookupTokenErr = ctx.LookupTokenErr
|
c.LookupTokenErr = ctx.LookupTokenErr
|
||||||
|
c.UseSessionStorageRedirect = ctx.UseSessionStorageRedirect
|
||||||
}
|
}
|
||||||
|
|
||||||
next.ServeHTTP(w, r)
|
next.ServeHTTP(w, r)
|
||||||
|
|
Loading…
Reference in New Issue