TUN-3484: OriginService that responds with configured HTTP status
This commit is contained in:
parent
d01770107e
commit
bc015995d8
|
@ -4,6 +4,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/url"
|
"net/url"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
@ -129,6 +130,13 @@ func validate(ingress []config.UnvalidatedIngressRule, defaults OriginRequestCon
|
||||||
// No validation necessary for unix socket filepath services
|
// No validation necessary for unix socket filepath services
|
||||||
path := strings.TrimPrefix(r.Service, prefix)
|
path := strings.TrimPrefix(r.Service, prefix)
|
||||||
service = &unixSocketPath{path: path}
|
service = &unixSocketPath{path: path}
|
||||||
|
} else if prefix := "http_status:"; strings.HasPrefix(r.Service, prefix) {
|
||||||
|
status, err := strconv.Atoi(strings.TrimPrefix(r.Service, prefix))
|
||||||
|
if err != nil {
|
||||||
|
return Ingress{}, errors.Wrap(err, "invalid HTTP status")
|
||||||
|
}
|
||||||
|
srv := newStatusCode(status)
|
||||||
|
service = &srv
|
||||||
} else if r.Service == "hello_world" || r.Service == "hello-world" || r.Service == "helloworld" {
|
} else if r.Service == "hello_world" || r.Service == "hello-world" || r.Service == "helloworld" {
|
||||||
service = new(helloWorld)
|
service = new(helloWorld)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -24,6 +24,7 @@ ingress:
|
||||||
func Test_parseIngress(t *testing.T) {
|
func Test_parseIngress(t *testing.T) {
|
||||||
localhost8000 := MustParseURL(t, "https://localhost:8000")
|
localhost8000 := MustParseURL(t, "https://localhost:8000")
|
||||||
localhost8001 := MustParseURL(t, "https://localhost:8001")
|
localhost8001 := MustParseURL(t, "https://localhost:8001")
|
||||||
|
fourOhFour := newStatusCode(404)
|
||||||
defaultConfig := setConfig(originRequestFromYAML(config.OriginRequestConfig{}), config.OriginRequestConfig{})
|
defaultConfig := setConfig(originRequestFromYAML(config.OriginRequestConfig{}), config.OriginRequestConfig{})
|
||||||
require.Equal(t, defaultKeepAliveConnections, defaultConfig.KeepAliveConnections)
|
require.Equal(t, defaultKeepAliveConnections, defaultConfig.KeepAliveConnections)
|
||||||
type args struct {
|
type args struct {
|
||||||
|
@ -172,6 +173,20 @@ ingress:
|
||||||
`},
|
`},
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "Valid HTTP status",
|
||||||
|
args: args{rawYAML: `
|
||||||
|
ingress:
|
||||||
|
- service: http_status:404
|
||||||
|
`},
|
||||||
|
want: []Rule{
|
||||||
|
{
|
||||||
|
Hostname: "",
|
||||||
|
Service: &fourOhFour,
|
||||||
|
Config: defaultConfig,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "Valid hello world service",
|
name: "Valid hello world service",
|
||||||
args: args{rawYAML: `
|
args: args{rawYAML: `
|
||||||
|
|
|
@ -223,6 +223,43 @@ func originRequiresProxy(staticHost string, cfg OriginRequestConfig) bool {
|
||||||
return staticHost != "" || cfg.BastionMode
|
return staticHost != "" || cfg.BastionMode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// statusCode is an OriginService that just responds with a given HTTP status.
|
||||||
|
// Typical use-case is "user wants the catch-all rule to just respond 404".
|
||||||
|
type statusCode struct {
|
||||||
|
resp *http.Response
|
||||||
|
}
|
||||||
|
|
||||||
|
func newStatusCode(status int) statusCode {
|
||||||
|
resp := &http.Response{
|
||||||
|
StatusCode: status,
|
||||||
|
Status: http.StatusText(status),
|
||||||
|
Body: new(NopReadCloser),
|
||||||
|
}
|
||||||
|
return statusCode{resp: resp}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *statusCode) String() string {
|
||||||
|
return fmt.Sprintf("HTTP %d", o.resp.StatusCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *statusCode) start(wg *sync.WaitGroup, log logger.Service, shutdownC <-chan struct{}, errC chan error, cfg OriginRequestConfig) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *statusCode) RoundTrip(_ *http.Request) (*http.Response, error) {
|
||||||
|
return o.resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type NopReadCloser struct{}
|
||||||
|
|
||||||
|
func (nrc *NopReadCloser) Read(buf []byte) (int, error) {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (nrc *NopReadCloser) Close() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func newHTTPTransport(service OriginService, cfg OriginRequestConfig) (*http.Transport, error) {
|
func newHTTPTransport(service OriginService, cfg OriginRequestConfig) (*http.Transport, error) {
|
||||||
originCertPool, err := tlsconfig.LoadOriginCA(cfg.CAPool, nil)
|
originCertPool, err := tlsconfig.LoadOriginCA(cfg.CAPool, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -4,6 +4,8 @@ import (
|
||||||
"net/url"
|
"net/url"
|
||||||
"regexp"
|
"regexp"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_rule_matches(t *testing.T) {
|
func Test_rule_matches(t *testing.T) {
|
||||||
|
@ -117,3 +119,19 @@ func Test_rule_matches(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestStaticHTTPStatus(t *testing.T) {
|
||||||
|
o := newStatusCode(404)
|
||||||
|
buf := make([]byte, 100)
|
||||||
|
|
||||||
|
sendReq := func() {
|
||||||
|
resp, err := o.RoundTrip(nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
_, err = resp.Body.Read(buf)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NoError(t, resp.Body.Close())
|
||||||
|
require.Equal(t, 404, resp.StatusCode)
|
||||||
|
}
|
||||||
|
sendReq()
|
||||||
|
sendReq()
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue