mirror of
https://github.com/labstack/echo.git
synced 2025-07-13 01:30:31 +02:00
Add Go 1.16 to CI and drop 1.12 specific code (#1850)
* Correct incorrect years in CHANGELOG.md * CI tests with last 4 versions. Remove 1.12 and below specific code * Rename proxy test
This commit is contained in:
8
.github/workflows/echo.yml
vendored
8
.github/workflows/echo.yml
vendored
@ -25,7 +25,9 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||||
go: [1.12, 1.13, 1.14, 1.15]
|
# Each major Go release is supported until there are two newer major releases. https://golang.org/doc/devel/release.html#policy
|
||||||
|
# Echo tests with last four major releases
|
||||||
|
go: [1.13, 1.14, 1.15, 1.16]
|
||||||
name: ${{ matrix.os }} @ Go ${{ matrix.go }}
|
name: ${{ matrix.os }} @ Go ${{ matrix.go }}
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
@ -59,7 +61,7 @@ jobs:
|
|||||||
go test -race --coverprofile=coverage.coverprofile --covermode=atomic ./...
|
go test -race --coverprofile=coverage.coverprofile --covermode=atomic ./...
|
||||||
|
|
||||||
- name: Upload coverage to Codecov
|
- name: Upload coverage to Codecov
|
||||||
if: success() && matrix.go == 1.15 && matrix.os == 'ubuntu-latest'
|
if: success() && matrix.go == 1.16 && matrix.os == 'ubuntu-latest'
|
||||||
uses: codecov/codecov-action@v1
|
uses: codecov/codecov-action@v1
|
||||||
with:
|
with:
|
||||||
token:
|
token:
|
||||||
@ -69,7 +71,7 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest]
|
os: [ubuntu-latest]
|
||||||
go: [1.15]
|
go: [1.16]
|
||||||
name: Benchmark comparison ${{ matrix.os }} @ Go ${{ matrix.go }}
|
name: Benchmark comparison ${{ matrix.os }} @ Go ${{ matrix.go }}
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
## v4.2.2 - 2020-04-07
|
## v4.2.2 - 2021-04-07
|
||||||
|
|
||||||
**Fixes**
|
**Fixes**
|
||||||
|
|
||||||
@ -10,7 +10,7 @@
|
|||||||
* Fix panic in redirect middleware on short host name (#1813)
|
* Fix panic in redirect middleware on short host name (#1813)
|
||||||
* Fix timeout middleware docs (#1836)
|
* Fix timeout middleware docs (#1836)
|
||||||
|
|
||||||
## v4.2.1 - 2020-03-08
|
## v4.2.1 - 2021-03-08
|
||||||
|
|
||||||
**Important notes**
|
**Important notes**
|
||||||
|
|
||||||
@ -32,7 +32,7 @@ A performance regression has been fixed, even bringing better performance than b
|
|||||||
This release was made possible by our **contributors**:
|
This release was made possible by our **contributors**:
|
||||||
aldas, clwluvw, lammel, Le0tk0k, maciej-jezierski, rkilingr, stffabi, withshubh
|
aldas, clwluvw, lammel, Le0tk0k, maciej-jezierski, rkilingr, stffabi, withshubh
|
||||||
|
|
||||||
## v4.2.0 - 2020-02-11
|
## v4.2.0 - 2021-02-11
|
||||||
|
|
||||||
**Important notes**
|
**Important notes**
|
||||||
|
|
||||||
|
@ -1,28 +0,0 @@
|
|||||||
// +build go1.13
|
|
||||||
|
|
||||||
package echo
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"net/http"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestHTTPError_Unwrap(t *testing.T) {
|
|
||||||
t.Run("non-internal", func(t *testing.T) {
|
|
||||||
err := NewHTTPError(http.StatusBadRequest, map[string]interface{}{
|
|
||||||
"code": 12,
|
|
||||||
})
|
|
||||||
|
|
||||||
assert.Nil(t, errors.Unwrap(err))
|
|
||||||
})
|
|
||||||
t.Run("internal", func(t *testing.T) {
|
|
||||||
err := NewHTTPError(http.StatusBadRequest, map[string]interface{}{
|
|
||||||
"code": 12,
|
|
||||||
})
|
|
||||||
err.SetInternal(errors.New("internal error"))
|
|
||||||
assert.Equal(t, "internal error", errors.Unwrap(err).Error())
|
|
||||||
})
|
|
||||||
}
|
|
17
echo_test.go
17
echo_test.go
@ -957,6 +957,23 @@ func TestHTTPError(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestHTTPError_Unwrap(t *testing.T) {
|
||||||
|
t.Run("non-internal", func(t *testing.T) {
|
||||||
|
err := NewHTTPError(http.StatusBadRequest, map[string]interface{}{
|
||||||
|
"code": 12,
|
||||||
|
})
|
||||||
|
|
||||||
|
assert.Nil(t, errors.Unwrap(err))
|
||||||
|
})
|
||||||
|
t.Run("internal", func(t *testing.T) {
|
||||||
|
err := NewHTTPError(http.StatusBadRequest, map[string]interface{}{
|
||||||
|
"code": 12,
|
||||||
|
})
|
||||||
|
err.SetInternal(errors.New("internal error"))
|
||||||
|
assert.Equal(t, "internal error", errors.Unwrap(err).Error())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func TestDefaultHTTPErrorHandler(t *testing.T) {
|
func TestDefaultHTTPErrorHandler(t *testing.T) {
|
||||||
e := New()
|
e := New()
|
||||||
e.Debug = true
|
e.Debug = true
|
||||||
|
@ -110,7 +110,7 @@ func CSRFWithConfig(config CSRFConfig) echo.MiddlewareFunc {
|
|||||||
if config.CookieMaxAge == 0 {
|
if config.CookieMaxAge == 0 {
|
||||||
config.CookieMaxAge = DefaultCSRFConfig.CookieMaxAge
|
config.CookieMaxAge = DefaultCSRFConfig.CookieMaxAge
|
||||||
}
|
}
|
||||||
if config.CookieSameSite == SameSiteNoneMode {
|
if config.CookieSameSite == http.SameSiteNoneMode {
|
||||||
config.CookieSecure = true
|
config.CookieSecure = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,12 +0,0 @@
|
|||||||
// +build go1.13
|
|
||||||
|
|
||||||
package middleware
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// SameSiteNoneMode required to be redefined for Go 1.12 support (see #1524)
|
|
||||||
SameSiteNoneMode http.SameSite = http.SameSiteNoneMode
|
|
||||||
)
|
|
@ -1,12 +0,0 @@
|
|||||||
// +build !go1.13
|
|
||||||
|
|
||||||
package middleware
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// SameSiteNoneMode required to be redefined for Go 1.12 support (see #1524)
|
|
||||||
SameSiteNoneMode http.SameSite = 4
|
|
||||||
)
|
|
@ -1,33 +0,0 @@
|
|||||||
// +build go1.13
|
|
||||||
|
|
||||||
package middleware
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
"net/http/httptest"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/labstack/echo/v4"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Test for SameSiteModeNone moved to separate file for Go 1.12 support
|
|
||||||
func TestCSRFWithSameSiteModeNone(t *testing.T) {
|
|
||||||
e := echo.New()
|
|
||||||
req := httptest.NewRequest(http.MethodGet, "/", nil)
|
|
||||||
rec := httptest.NewRecorder()
|
|
||||||
c := e.NewContext(req, rec)
|
|
||||||
|
|
||||||
csrf := CSRFWithConfig(CSRFConfig{
|
|
||||||
CookieSameSite: SameSiteNoneMode,
|
|
||||||
})
|
|
||||||
|
|
||||||
h := csrf(func(c echo.Context) error {
|
|
||||||
return c.String(http.StatusOK, "test")
|
|
||||||
})
|
|
||||||
|
|
||||||
r := h(c)
|
|
||||||
assert.NoError(t, r)
|
|
||||||
assert.Regexp(t, "SameSite=None", rec.Header()["Set-Cookie"])
|
|
||||||
assert.Regexp(t, "Secure", rec.Header()["Set-Cookie"])
|
|
||||||
}
|
|
@ -138,3 +138,23 @@ func TestCSRFWithSameSiteDefaultMode(t *testing.T) {
|
|||||||
fmt.Println(rec.Header()["Set-Cookie"])
|
fmt.Println(rec.Header()["Set-Cookie"])
|
||||||
assert.NotRegexp(t, "SameSite=", rec.Header()["Set-Cookie"])
|
assert.NotRegexp(t, "SameSite=", rec.Header()["Set-Cookie"])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCSRFWithSameSiteModeNone(t *testing.T) {
|
||||||
|
e := echo.New()
|
||||||
|
req := httptest.NewRequest(http.MethodGet, "/", nil)
|
||||||
|
rec := httptest.NewRecorder()
|
||||||
|
c := e.NewContext(req, rec)
|
||||||
|
|
||||||
|
csrf := CSRFWithConfig(CSRFConfig{
|
||||||
|
CookieSameSite: http.SameSiteNoneMode,
|
||||||
|
})
|
||||||
|
|
||||||
|
h := csrf(func(c echo.Context) error {
|
||||||
|
return c.String(http.StatusOK, "test")
|
||||||
|
})
|
||||||
|
|
||||||
|
r := h(c)
|
||||||
|
assert.NoError(t, r)
|
||||||
|
assert.Regexp(t, "SameSite=None", rec.Header()["Set-Cookie"])
|
||||||
|
assert.Regexp(t, "Secure", rec.Header()["Set-Cookie"])
|
||||||
|
}
|
||||||
|
@ -1,13 +1,16 @@
|
|||||||
package middleware
|
package middleware
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/http/httputil"
|
||||||
"net/url"
|
"net/url"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
@ -264,3 +267,37 @@ func ProxyWithConfig(config ProxyConfig) echo.MiddlewareFunc {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// StatusCodeContextCanceled is a custom HTTP status code for situations
|
||||||
|
// where a client unexpectedly closed the connection to the server.
|
||||||
|
// As there is no standard error code for "client closed connection", but
|
||||||
|
// various well-known HTTP clients and server implement this HTTP code we use
|
||||||
|
// 499 too instead of the more problematic 5xx, which does not allow to detect this situation
|
||||||
|
const StatusCodeContextCanceled = 499
|
||||||
|
|
||||||
|
func proxyHTTP(tgt *ProxyTarget, c echo.Context, config ProxyConfig) http.Handler {
|
||||||
|
proxy := httputil.NewSingleHostReverseProxy(tgt.URL)
|
||||||
|
proxy.ErrorHandler = func(resp http.ResponseWriter, req *http.Request, err error) {
|
||||||
|
desc := tgt.URL.String()
|
||||||
|
if tgt.Name != "" {
|
||||||
|
desc = fmt.Sprintf("%s(%s)", tgt.Name, tgt.URL.String())
|
||||||
|
}
|
||||||
|
// If the client canceled the request (usually by closing the connection), we can report a
|
||||||
|
// client error (4xx) instead of a server error (5xx) to correctly identify the situation.
|
||||||
|
// The Go standard library (at of late 2020) wraps the exported, standard
|
||||||
|
// context.Canceled error with unexported garbage value requiring a substring check, see
|
||||||
|
// https://github.com/golang/go/blob/6965b01ea248cabb70c3749fd218b36089a21efb/src/net/net.go#L416-L430
|
||||||
|
if err == context.Canceled || strings.Contains(err.Error(), "operation was canceled") {
|
||||||
|
httpError := echo.NewHTTPError(StatusCodeContextCanceled, fmt.Sprintf("client closed connection: %v", err))
|
||||||
|
httpError.Internal = err
|
||||||
|
c.Set("_error", httpError)
|
||||||
|
} else {
|
||||||
|
httpError := echo.NewHTTPError(http.StatusBadGateway, fmt.Sprintf("remote %s unreachable, could not forward: %v", desc, err))
|
||||||
|
httpError.Internal = err
|
||||||
|
c.Set("_error", httpError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
proxy.Transport = config.Transport
|
||||||
|
proxy.ModifyResponse = config.ModifyResponse
|
||||||
|
return proxy
|
||||||
|
}
|
||||||
|
@ -1,47 +0,0 @@
|
|||||||
// +build go1.11
|
|
||||||
|
|
||||||
package middleware
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"net/http/httputil"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/labstack/echo/v4"
|
|
||||||
)
|
|
||||||
|
|
||||||
// StatusCodeContextCanceled is a custom HTTP status code for situations
|
|
||||||
// where a client unexpectedly closed the connection to the server.
|
|
||||||
// As there is no standard error code for "client closed connection", but
|
|
||||||
// various well-known HTTP clients and server implement this HTTP code we use
|
|
||||||
// 499 too instead of the more problematic 5xx, which does not allow to detect this situation
|
|
||||||
const StatusCodeContextCanceled = 499
|
|
||||||
|
|
||||||
func proxyHTTP(tgt *ProxyTarget, c echo.Context, config ProxyConfig) http.Handler {
|
|
||||||
proxy := httputil.NewSingleHostReverseProxy(tgt.URL)
|
|
||||||
proxy.ErrorHandler = func(resp http.ResponseWriter, req *http.Request, err error) {
|
|
||||||
desc := tgt.URL.String()
|
|
||||||
if tgt.Name != "" {
|
|
||||||
desc = fmt.Sprintf("%s(%s)", tgt.Name, tgt.URL.String())
|
|
||||||
}
|
|
||||||
// If the client canceled the request (usually by closing the connection), we can report a
|
|
||||||
// client error (4xx) instead of a server error (5xx) to correctly identify the situation.
|
|
||||||
// The Go standard library (at of late 2020) wraps the exported, standard
|
|
||||||
// context.Canceled error with unexported garbage value requiring a substring check, see
|
|
||||||
// https://github.com/golang/go/blob/6965b01ea248cabb70c3749fd218b36089a21efb/src/net/net.go#L416-L430
|
|
||||||
if err == context.Canceled || strings.Contains(err.Error(), "operation was canceled") {
|
|
||||||
httpError := echo.NewHTTPError(StatusCodeContextCanceled, fmt.Sprintf("client closed connection: %v", err))
|
|
||||||
httpError.Internal = err
|
|
||||||
c.Set("_error", httpError)
|
|
||||||
} else {
|
|
||||||
httpError := echo.NewHTTPError(http.StatusBadGateway, fmt.Sprintf("remote %s unreachable, could not forward: %v", desc, err))
|
|
||||||
httpError.Internal = err
|
|
||||||
c.Set("_error", httpError)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
proxy.Transport = config.Transport
|
|
||||||
proxy.ModifyResponse = config.ModifyResponse
|
|
||||||
return proxy
|
|
||||||
}
|
|
@ -1,14 +0,0 @@
|
|||||||
// +build !go1.11
|
|
||||||
|
|
||||||
package middleware
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
"net/http/httputil"
|
|
||||||
|
|
||||||
"github.com/labstack/echo/v4"
|
|
||||||
)
|
|
||||||
|
|
||||||
func proxyHTTP(t *ProxyTarget, c echo.Context, config ProxyConfig) http.Handler {
|
|
||||||
return httputil.NewSingleHostReverseProxy(t.URL)
|
|
||||||
}
|
|
@ -1,86 +0,0 @@
|
|||||||
// +build go1.11
|
|
||||||
|
|
||||||
package middleware
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"net/http"
|
|
||||||
"net/http/httptest"
|
|
||||||
"net/url"
|
|
||||||
"sync"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/labstack/echo/v4"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestProxy_1_11(t *testing.T) {
|
|
||||||
// Setup
|
|
||||||
url1, _ := url.Parse("http://127.0.0.1:27121")
|
|
||||||
url2, _ := url.Parse("http://127.0.0.1:27122")
|
|
||||||
|
|
||||||
targets := []*ProxyTarget{
|
|
||||||
{
|
|
||||||
Name: "target 1",
|
|
||||||
URL: url1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "target 2",
|
|
||||||
URL: url2,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
rb := NewRandomBalancer(nil)
|
|
||||||
// must add targets:
|
|
||||||
for _, target := range targets {
|
|
||||||
assert.True(t, rb.AddTarget(target))
|
|
||||||
}
|
|
||||||
|
|
||||||
// must ignore duplicates:
|
|
||||||
for _, target := range targets {
|
|
||||||
assert.False(t, rb.AddTarget(target))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Random
|
|
||||||
e := echo.New()
|
|
||||||
e.Use(Proxy(rb))
|
|
||||||
req := httptest.NewRequest(http.MethodGet, "/", nil)
|
|
||||||
rec := httptest.NewRecorder()
|
|
||||||
|
|
||||||
// Remote unreachable
|
|
||||||
rec = httptest.NewRecorder()
|
|
||||||
req.URL.Path = "/api/users"
|
|
||||||
e.ServeHTTP(rec, req)
|
|
||||||
assert.Equal(t, "/api/users", req.URL.Path)
|
|
||||||
assert.Equal(t, http.StatusBadGateway, rec.Code)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestClientCancelConnectionResultsHTTPCode499(t *testing.T) {
|
|
||||||
var timeoutStop sync.WaitGroup
|
|
||||||
timeoutStop.Add(1)
|
|
||||||
HTTPTarget := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
timeoutStop.Wait() // wait until we have canceled the request
|
|
||||||
w.WriteHeader(http.StatusOK)
|
|
||||||
}))
|
|
||||||
defer HTTPTarget.Close()
|
|
||||||
targetURL, _ := url.Parse(HTTPTarget.URL)
|
|
||||||
target := &ProxyTarget{
|
|
||||||
Name: "target",
|
|
||||||
URL: targetURL,
|
|
||||||
}
|
|
||||||
rb := NewRandomBalancer(nil)
|
|
||||||
assert.True(t, rb.AddTarget(target))
|
|
||||||
e := echo.New()
|
|
||||||
e.Use(Proxy(rb))
|
|
||||||
rec := httptest.NewRecorder()
|
|
||||||
req := httptest.NewRequest(http.MethodGet, "/", nil)
|
|
||||||
ctx, cancel := context.WithCancel(req.Context())
|
|
||||||
req = req.WithContext(ctx)
|
|
||||||
go func() {
|
|
||||||
time.Sleep(10 * time.Millisecond)
|
|
||||||
cancel()
|
|
||||||
}()
|
|
||||||
e.ServeHTTP(rec, req)
|
|
||||||
timeoutStop.Done()
|
|
||||||
assert.Equal(t, 499, rec.Code)
|
|
||||||
}
|
|
@ -2,6 +2,7 @@ package middleware
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net"
|
"net"
|
||||||
@ -9,7 +10,9 @@ import (
|
|||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"net/url"
|
"net/url"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
@ -302,3 +305,73 @@ func TestProxyRewriteRegex(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestProxyError(t *testing.T) {
|
||||||
|
// Setup
|
||||||
|
url1, _ := url.Parse("http://127.0.0.1:27121")
|
||||||
|
url2, _ := url.Parse("http://127.0.0.1:27122")
|
||||||
|
|
||||||
|
targets := []*ProxyTarget{
|
||||||
|
{
|
||||||
|
Name: "target 1",
|
||||||
|
URL: url1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "target 2",
|
||||||
|
URL: url2,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
rb := NewRandomBalancer(nil)
|
||||||
|
// must add targets:
|
||||||
|
for _, target := range targets {
|
||||||
|
assert.True(t, rb.AddTarget(target))
|
||||||
|
}
|
||||||
|
|
||||||
|
// must ignore duplicates:
|
||||||
|
for _, target := range targets {
|
||||||
|
assert.False(t, rb.AddTarget(target))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Random
|
||||||
|
e := echo.New()
|
||||||
|
e.Use(Proxy(rb))
|
||||||
|
req := httptest.NewRequest(http.MethodGet, "/", nil)
|
||||||
|
rec := httptest.NewRecorder()
|
||||||
|
|
||||||
|
// Remote unreachable
|
||||||
|
rec = httptest.NewRecorder()
|
||||||
|
req.URL.Path = "/api/users"
|
||||||
|
e.ServeHTTP(rec, req)
|
||||||
|
assert.Equal(t, "/api/users", req.URL.Path)
|
||||||
|
assert.Equal(t, http.StatusBadGateway, rec.Code)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestClientCancelConnectionResultsHTTPCode499(t *testing.T) {
|
||||||
|
var timeoutStop sync.WaitGroup
|
||||||
|
timeoutStop.Add(1)
|
||||||
|
HTTPTarget := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
timeoutStop.Wait() // wait until we have canceled the request
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
}))
|
||||||
|
defer HTTPTarget.Close()
|
||||||
|
targetURL, _ := url.Parse(HTTPTarget.URL)
|
||||||
|
target := &ProxyTarget{
|
||||||
|
Name: "target",
|
||||||
|
URL: targetURL,
|
||||||
|
}
|
||||||
|
rb := NewRandomBalancer(nil)
|
||||||
|
assert.True(t, rb.AddTarget(target))
|
||||||
|
e := echo.New()
|
||||||
|
e.Use(Proxy(rb))
|
||||||
|
rec := httptest.NewRecorder()
|
||||||
|
req := httptest.NewRequest(http.MethodGet, "/", nil)
|
||||||
|
ctx, cancel := context.WithCancel(req.Context())
|
||||||
|
req = req.WithContext(ctx)
|
||||||
|
go func() {
|
||||||
|
time.Sleep(10 * time.Millisecond)
|
||||||
|
cancel()
|
||||||
|
}()
|
||||||
|
e.ServeHTTP(rec, req)
|
||||||
|
timeoutStop.Done()
|
||||||
|
assert.Equal(t, 499, rec.Code)
|
||||||
|
}
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
// +build go1.13
|
|
||||||
|
|
||||||
package middleware
|
package middleware
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
// +build go1.13
|
|
||||||
|
|
||||||
package middleware
|
package middleware
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
Reference in New Issue
Block a user