Skip to content

Commit

Permalink
ngrok: add option to auto-rewrite the host header on ListenAndForward
Browse files Browse the repository at this point in the history
  • Loading branch information
jrobsonchase committed Oct 31, 2023
1 parent 77b6cd9 commit c0631f8
Show file tree
Hide file tree
Showing 30 changed files with 85 additions and 51 deletions.
2 changes: 1 addition & 1 deletion config/basic_auth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
)

func TestBasicAuth(t *testing.T) {
cases := testCases[httpOptions, proto.HTTPEndpoint]{
cases := testCases[*httpOptions, proto.HTTPEndpoint]{
{
name: "single",
opts: HTTPEndpoint(WithBasicAuth("foo", "bar")),
Expand Down
6 changes: 3 additions & 3 deletions config/cidr_restrictions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,15 +122,15 @@ func testCIDRRestrictions[T tunnelConfigPrivate, O any, OT any](t *testing.T,
}

func TestCIDRRestrictions(t *testing.T) {
testCIDRRestrictions[httpOptions](t, HTTPEndpoint,
testCIDRRestrictions[*httpOptions](t, HTTPEndpoint,
func(h *proto.HTTPEndpoint) *pb.MiddlewareConfiguration_IPRestriction {
return h.IPRestriction
})
testCIDRRestrictions[tcpOptions](t, TCPEndpoint,
testCIDRRestrictions[*tcpOptions](t, TCPEndpoint,
func(h *proto.TCPEndpoint) *pb.MiddlewareConfiguration_IPRestriction {
return h.IPRestriction
})
testCIDRRestrictions[tlsOptions](t, TLSEndpoint,
testCIDRRestrictions[*tlsOptions](t, TLSEndpoint,
func(h *proto.TLSEndpoint) *pb.MiddlewareConfiguration_IPRestriction {
return h.IPRestriction
})
Expand Down
2 changes: 1 addition & 1 deletion config/circuit_breaker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
)

func TestCircuitBreaker(t *testing.T) {
cases := testCases[httpOptions, proto.HTTPEndpoint]{
cases := testCases[*httpOptions, proto.HTTPEndpoint]{
{
name: "absent",
opts: HTTPEndpoint(),
Expand Down
2 changes: 1 addition & 1 deletion config/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,4 @@ func (cfg *commonOpts) getForwardsTo() string {
return cfg.ForwardsTo
}

func (cfg commonOpts) tunnelOptions() {}
func (cfg *commonOpts) tunnelOptions() {}
2 changes: 1 addition & 1 deletion config/compression_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
)

func TestCompression(t *testing.T) {
cases := testCases[httpOptions, proto.HTTPEndpoint]{
cases := testCases[*httpOptions, proto.HTTPEndpoint]{
{
name: "absent",
opts: HTTPEndpoint(),
Expand Down
4 changes: 2 additions & 2 deletions config/domain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,10 @@ func testDomain[T tunnelConfigPrivate, O any, OT any](t *testing.T,
}

func TestDomain(t *testing.T) {
testDomain[httpOptions](t, HTTPEndpoint, func(opts *proto.HTTPEndpoint) string {
testDomain[*httpOptions](t, HTTPEndpoint, func(opts *proto.HTTPEndpoint) string {
return opts.Domain
})
testDomain[tlsOptions](t, TLSEndpoint, func(opts *proto.TLSEndpoint) string {
testDomain[*tlsOptions](t, TLSEndpoint, func(opts *proto.TLSEndpoint) string {
return opts.Domain
})
}
8 changes: 4 additions & 4 deletions config/forwards_to_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ func testForwardsTo[T tunnelConfigPrivate, OT any](t *testing.T,
}

func TestForwardsTo(t *testing.T) {
testForwardsTo[httpOptions](t, HTTPEndpoint)
testForwardsTo[tlsOptions](t, TLSEndpoint)
testForwardsTo[tcpOptions](t, TCPEndpoint)
testForwardsTo[labeledOptions](t, LabeledTunnel)
testForwardsTo[*httpOptions](t, HTTPEndpoint)
testForwardsTo[*tlsOptions](t, TLSEndpoint)
testForwardsTo[*tcpOptions](t, TCPEndpoint)
testForwardsTo[*labeledOptions](t, LabeledTunnel)
}
13 changes: 10 additions & 3 deletions config/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package config
import (
"crypto/x509"
"net/http"
"net/url"

"golang.ngrok.com/ngrok/internal/pb"
"golang.ngrok.com/ngrok/internal/tunnel/proto"
Expand All @@ -24,7 +25,7 @@ func HTTPEndpoint(opts ...HTTPEndpointOption) Tunnel {
for _, opt := range opts {
opt.ApplyHTTP(&cfg)
}
return cfg
return &cfg
}

type httpOptions struct {
Expand Down Expand Up @@ -63,6 +64,9 @@ type httpOptions struct {
// Headers to be added to or removed from all responses at the ngrok edge.
ResponseHeaders *headers

// Auto-rewrite host header on ListenAndForward?
RewriteHostHeader bool

// Credentials for basic authentication.
// If empty, basic authentication is disabled.
BasicAuth []basicAuth
Expand Down Expand Up @@ -126,8 +130,11 @@ func (cfg httpOptions) ForwardsTo() string {
return cfg.commonOpts.getForwardsTo()
}

func (cfg httpOptions) WithForwardsTo(hostname string) {
cfg.commonOpts.ForwardsTo = hostname
func (cfg *httpOptions) WithForwardsTo(url *url.URL) {
cfg.commonOpts.ForwardsTo = url.Host
if cfg.RewriteHostHeader {
WithRequestHeader("host", url.Host).ApplyHTTP(cfg)
}
}

func (cfg httpOptions) Extra() proto.BindExtra {
Expand Down
12 changes: 12 additions & 0 deletions config/http_headers.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,18 @@ func (h responseHeaders) ApplyHTTP(cfg *httpOptions) {
cfg.ResponseHeaders = cfg.ResponseHeaders.merge(headers(h))
}

// WithHostHeaderRewrite will automatically set the `Host` header to the one in
// the URL passed to `ListenAndForward`. Does nothing if using `Listen`.
// Defaults to `false`.
//
// If you need to set the host header to a specific value, use
// `WithRequestHeader("host", "some.host.com")` instead.
func WithHostHeaderRewrite(rewrite bool) HTTPEndpointOption {
return httpOptionFunc(func(cfg *httpOptions) {
cfg.RewriteHostHeader = rewrite
})
}

// WithRequestHeader adds a header to all requests to this edge.
func WithRequestHeader(name, value string) HTTPEndpointOption {
return requestHeaders(headers{
Expand Down
2 changes: 1 addition & 1 deletion config/http_headers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
)

func TestHTTPHeaders(t *testing.T) {
cases := testCases[httpOptions, proto.HTTPEndpoint]{
cases := testCases[*httpOptions, proto.HTTPEndpoint]{
{
name: "absent",
opts: HTTPEndpoint(),
Expand Down
2 changes: 1 addition & 1 deletion config/http_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
)

func TestHTTP(t *testing.T) {
cases := testCases[httpOptions, proto.HTTPEndpoint]{
cases := testCases[*httpOptions, proto.HTTPEndpoint]{
{
name: "empty",
opts: HTTPEndpoint(),
Expand Down
7 changes: 4 additions & 3 deletions config/labeled.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package config

import (
"net/http"
"net/url"

"golang.ngrok.com/ngrok/internal/tunnel/proto"
)
Expand All @@ -22,7 +23,7 @@ func LabeledTunnel(opts ...LabeledTunnelOption) Tunnel {
for _, opt := range opts {
opt.ApplyLabeled(&cfg)
}
return cfg
return &cfg
}

// Options for labeled tunnels.
Expand Down Expand Up @@ -53,8 +54,8 @@ func (cfg labeledOptions) ForwardsTo() string {
return cfg.commonOpts.getForwardsTo()
}

func (cfg labeledOptions) WithForwardsTo(hostname string) {
cfg.commonOpts.ForwardsTo = hostname
func (cfg *labeledOptions) WithForwardsTo(url *url.URL) {
cfg.commonOpts.ForwardsTo = url.Host
}

func (cfg labeledOptions) Extra() proto.BindExtra {
Expand Down
2 changes: 1 addition & 1 deletion config/labeled_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
)

func TestLabeled(t *testing.T) {
cases := testCases[labeledOptions, proto.LabelOptions]{
cases := testCases[*labeledOptions, proto.LabelOptions]{
{
name: "simple",
opts: LabeledTunnel(WithLabel("foo", "bar")),
Expand Down
8 changes: 4 additions & 4 deletions config/metadata_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ func testMetadata[T tunnelConfigPrivate, OT any](t *testing.T,
}

func TestMetadata(t *testing.T) {
testMetadata[httpOptions](t, HTTPEndpoint)
testMetadata[tlsOptions](t, TLSEndpoint)
testMetadata[tcpOptions](t, TCPEndpoint)
testMetadata[labeledOptions](t, LabeledTunnel)
testMetadata[*httpOptions](t, HTTPEndpoint)
testMetadata[*tlsOptions](t, TLSEndpoint)
testMetadata[*tcpOptions](t, TCPEndpoint)
testMetadata[*labeledOptions](t, LabeledTunnel)
}
4 changes: 2 additions & 2 deletions config/mutual_tls_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,10 @@ func testMutualTLS[T tunnelConfigPrivate, O any, OT any](t *testing.T,
}

func TestMutualTLS(t *testing.T) {
testMutualTLS[httpOptions](t, HTTPEndpoint, func(opts *proto.HTTPEndpoint) *pb.MiddlewareConfiguration_MutualTLS {
testMutualTLS[*httpOptions](t, HTTPEndpoint, func(opts *proto.HTTPEndpoint) *pb.MiddlewareConfiguration_MutualTLS {
return opts.MutualTLSCA
})
testMutualTLS[tlsOptions](t, TLSEndpoint, func(opts *proto.TLSEndpoint) *pb.MiddlewareConfiguration_MutualTLS {
testMutualTLS[*tlsOptions](t, TLSEndpoint, func(opts *proto.TLSEndpoint) *pb.MiddlewareConfiguration_MutualTLS {
return opts.MutualTLSAtEdge
})
}
2 changes: 1 addition & 1 deletion config/oauth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
)

func TestOAuth(t *testing.T) {
cases := testCases[httpOptions, proto.HTTPEndpoint]{
cases := testCases[*httpOptions, proto.HTTPEndpoint]{
{
name: "absent",
opts: HTTPEndpoint(),
Expand Down
2 changes: 1 addition & 1 deletion config/oidc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
)

func TestOIDC(t *testing.T) {
cases := testCases[httpOptions, proto.HTTPEndpoint]{
cases := testCases[*httpOptions, proto.HTTPEndpoint]{
{
name: "absent",
opts: HTTPEndpoint(),
Expand Down
6 changes: 3 additions & 3 deletions config/proxy_proto_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,13 @@ func testProxyProto[T tunnelConfigPrivate, O any, OT any](t *testing.T,
}

func TestProxyProto(t *testing.T) {
testProxyProto[httpOptions](t, HTTPEndpoint, func(opts *proto.HTTPEndpoint) proto.ProxyProto {
testProxyProto[*httpOptions](t, HTTPEndpoint, func(opts *proto.HTTPEndpoint) proto.ProxyProto {
return opts.ProxyProto
})
testProxyProto[tlsOptions](t, TLSEndpoint, func(opts *proto.TLSEndpoint) proto.ProxyProto {
testProxyProto[*tlsOptions](t, TLSEndpoint, func(opts *proto.TLSEndpoint) proto.ProxyProto {
return opts.ProxyProto
})
testProxyProto[tcpOptions](t, TCPEndpoint, func(opts *proto.TCPEndpoint) proto.ProxyProto {
testProxyProto[*tcpOptions](t, TCPEndpoint, func(opts *proto.TCPEndpoint) proto.ProxyProto {
return opts.ProxyProto
})
}
2 changes: 1 addition & 1 deletion config/scheme_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
)

func TestScheme(t *testing.T) {
cases := testCases[httpOptions, proto.HTTPEndpoint]{
cases := testCases[*httpOptions, proto.HTTPEndpoint]{
{
name: "default",
opts: HTTPEndpoint(),
Expand Down
7 changes: 4 additions & 3 deletions config/tcp.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package config

import (
"net/http"
"net/url"

"golang.ngrok.com/ngrok/internal/tunnel/proto"
)
Expand All @@ -22,7 +23,7 @@ func TCPEndpoint(opts ...TCPEndpointOption) Tunnel {
for _, opt := range opts {
opt.ApplyTCP(&cfg)
}
return cfg
return &cfg
}

// The options for a TCP edge.
Expand Down Expand Up @@ -55,8 +56,8 @@ func (cfg tcpOptions) ForwardsTo() string {
return cfg.commonOpts.getForwardsTo()
}

func (cfg tcpOptions) WithForwardsTo(hostname string) {
cfg.commonOpts.ForwardsTo = hostname
func (cfg *tcpOptions) WithForwardsTo(url *url.URL) {
cfg.commonOpts.ForwardsTo = url.Host
}

func (cfg tcpOptions) Extra() proto.BindExtra {
Expand Down
2 changes: 1 addition & 1 deletion config/tcp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
)

func TestTCP(t *testing.T) {
cases := testCases[tcpOptions, proto.TCPEndpoint]{
cases := testCases[*tcpOptions, proto.TCPEndpoint]{
{
name: "empty",
opts: TCPEndpoint(),
Expand Down
7 changes: 4 additions & 3 deletions config/tls.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package config
import (
"crypto/x509"
"net/http"
"net/url"

"golang.ngrok.com/ngrok/internal/pb"
"golang.ngrok.com/ngrok/internal/tunnel/proto"
Expand All @@ -24,7 +25,7 @@ func TLSEndpoint(opts ...TLSEndpointOption) Tunnel {
for _, opt := range opts {
opt.ApplyTLS(&cfg)
}
return cfg
return &cfg
}

// The options for TLS edges.
Expand Down Expand Up @@ -85,8 +86,8 @@ func (cfg tlsOptions) ForwardsTo() string {
return cfg.commonOpts.getForwardsTo()
}

func (cfg tlsOptions) WithForwardsTo(hostname string) {
cfg.commonOpts.ForwardsTo = hostname
func (cfg *tlsOptions) WithForwardsTo(url *url.URL) {
cfg.commonOpts.ForwardsTo = url.Host
}

func (cfg tlsOptions) Extra() proto.BindExtra {
Expand Down
2 changes: 1 addition & 1 deletion config/tls_termination_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
)

func TestTLSTermination(t *testing.T) {
cases := testCases[tlsOptions, proto.TLSEndpoint]{
cases := testCases[*tlsOptions, proto.TLSEndpoint]{
{
name: "absent",
opts: TLSEndpoint(),
Expand Down
2 changes: 1 addition & 1 deletion config/tls_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
)

func TestTLS(t *testing.T) {
cases := testCases[tlsOptions, proto.TLSEndpoint]{
cases := testCases[*tlsOptions, proto.TLSEndpoint]{
{
name: "basic",
opts: TLSEndpoint(),
Expand Down
10 changes: 8 additions & 2 deletions config/tunnel_config.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package config

import "golang.ngrok.com/ngrok/internal/tunnel/proto"
import (
"net/url"

"golang.ngrok.com/ngrok/internal/tunnel/proto"
)

// Tunnel is a marker interface for options that can be used to start
// tunnels.
Expand All @@ -14,9 +18,11 @@ type Tunnel interface {
// the public interface with internal details.
type tunnelConfigPrivate interface {
ForwardsTo() string
WithForwardsTo(string)
Extra() proto.BindExtra
Proto() string
Opts() any
Labels() map[string]string
// Extra config when auto-forwarding to a URL.
// Normal operation should use the functional builder.
WithForwardsTo(*url.URL)
}
2 changes: 1 addition & 1 deletion config/user_agent_filter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ func testUserAgentFilter[T tunnelConfigPrivate, O any, OT any](t *testing.T,
}

func TestUserAgentFilter(t *testing.T) {
testUserAgentFilter[httpOptions](t, HTTPEndpoint,
testUserAgentFilter[*httpOptions](t, HTTPEndpoint,
func(h *proto.HTTPEndpoint) *pb.MiddlewareConfiguration_UserAgentFilter {
return h.UserAgentFilter
})
Expand Down
2 changes: 1 addition & 1 deletion config/webhook_verification_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
)

func TestWebhookVerification(t *testing.T) {
cases := testCases[httpOptions, proto.HTTPEndpoint]{
cases := testCases[*httpOptions, proto.HTTPEndpoint]{
{
name: "absent",
opts: HTTPEndpoint(),
Expand Down
2 changes: 1 addition & 1 deletion config/websocket_tcp_conversion_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
)

func TestWebsocketTCPConversion(t *testing.T) {
cases := testCases[httpOptions, proto.HTTPEndpoint]{
cases := testCases[*httpOptions, proto.HTTPEndpoint]{
{
name: "absent",
opts: HTTPEndpoint(),
Expand Down
Loading

0 comments on commit c0631f8

Please sign in to comment.