Skip to content

Commit

Permalink
Add onfiguration option to override Host header.
Browse files Browse the repository at this point in the history
  • Loading branch information
enuret committed Dec 22, 2023
1 parent 885210b commit 99f34b3
Show file tree
Hide file tree
Showing 17 changed files with 136 additions and 13 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
- Add `WithResourceAsConstantLabels` option to apply resource attributes for every metric emitted by the Prometheus exporter. (#4733)
- Experimental cardinality limiting is added to the metric SDK.
See [metric documentation](./sdk/metric/EXPERIMENTAL.md#cardinality-limit) for more information about this feature and how to enable it. (#4457)
- Add `WithHostHeader` config option to override Host header in opentelemetry requests (#4777)

### Changed

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ type (
Insecure bool
TLSCfg *tls.Config
Headers map[string]string
HostHeader string
Compression Compression
Timeout time.Duration
URLPath string
Expand Down Expand Up @@ -331,6 +332,13 @@ func WithHeaders(headers map[string]string) GenericOption {
})
}

func WithHostHeader(host string) GenericOption {
return newGenericOption(func(cfg Config) Config {
cfg.Metrics.HostHeader = host
return cfg
})

Check warning on line 339 in exporters/otlp/otlpmetric/otlpmetricgrpc/internal/oconf/options.go

View check run for this annotation

Codecov / codecov/patch

exporters/otlp/otlpmetric/otlpmetricgrpc/internal/oconf/options.go#L335-L339

Added lines #L335 - L339 were not covered by tests
}

func WithTimeout(duration time.Duration) GenericOption {
return newGenericOption(func(cfg Config) Config {
cfg.Metrics.Timeout = duration
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -197,9 +197,10 @@ func (e *HTTPResponseError) Unwrap() error { return e.Err }
type HTTPCollector struct {
plainTextResponse bool

headersMu sync.Mutex
headers http.Header
storage *Storage
headersMu sync.Mutex
headers http.Header
hostHeader string
storage *Storage

resultCh <-chan ExportResult
listener net.Listener
Expand Down Expand Up @@ -299,6 +300,10 @@ func (c *HTTPCollector) Headers() map[string][]string {
return c.headers.Clone()
}

func (c *HTTPCollector) HostHeader() string {
return c.hostHeader

Check warning on line 304 in exporters/otlp/otlpmetric/otlpmetricgrpc/internal/otest/collector.go

View check run for this annotation

Codecov / codecov/patch

exporters/otlp/otlpmetric/otlpmetricgrpc/internal/otest/collector.go#L303-L304

Added lines #L303 - L304 were not covered by tests
}

func (c *HTTPCollector) handler(w http.ResponseWriter, r *http.Request) {
c.respond(w, c.record(r))
}
Expand Down Expand Up @@ -334,6 +339,8 @@ func (c *HTTPCollector) record(r *http.Request) ExportResult {
}
c.headersMu.Unlock()

c.hostHeader = r.Host

Check warning on line 343 in exporters/otlp/otlpmetric/otlpmetricgrpc/internal/otest/collector.go

View check run for this annotation

Codecov / codecov/patch

exporters/otlp/otlpmetric/otlpmetricgrpc/internal/otest/collector.go#L342-L343

Added lines #L342 - L343 were not covered by tests
if c.resultCh != nil {
return <-c.resultCh
}
Expand Down
5 changes: 5 additions & 0 deletions exporters/otlp/otlpmetric/otlpmetrichttp/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ func newClient(cfg oconf.Config) (*client, error) {
if cfg.Metrics.Insecure {
u.Scheme = "http"
}

// Body is set when this is cloned during upload.
req, err := http.NewRequest(http.MethodPost, u.String(), http.NoBody)
if err != nil {
Expand All @@ -99,6 +100,10 @@ func newClient(cfg oconf.Config) (*client, error) {
}
req.Header.Set("Content-Type", "application/x-protobuf")

if cfg.Metrics.HostHeader != "" {
req.Host = cfg.Metrics.HostHeader
}

return &client{
compression: Compression(cfg.Metrics.Compression),
req: req,
Expand Down
15 changes: 14 additions & 1 deletion exporters/otlp/otlpmetric/otlpmetrichttp/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
// 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
// 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,
Expand Down Expand Up @@ -123,6 +123,19 @@ func TestConfig(t *testing.T) {
assert.Equal(t, got[key], []string{headers[key]})
})

t.Run("WithHostHeader", func(t *testing.T) {
hostHeader := "test-host"
exp, coll := factoryFunc("", nil, WithHostHeader(hostHeader))
ctx := context.Background()
t.Cleanup(func() { require.NoError(t, coll.Shutdown(ctx)) })
require.NoError(t, exp.Export(ctx, &metricdata.ResourceMetrics{}))
// Ensure everything is flushed.
require.NoError(t, exp.Shutdown(ctx))

got := coll.HostHeader()
assert.Equal(t, got, hostHeader)
})

t.Run("WithTimeout", func(t *testing.T) {
// Do not send on rCh so the Collector never responds to the client.
rCh := make(chan otest.ExportResult)
Expand Down
6 changes: 6 additions & 0 deletions exporters/otlp/otlpmetric/otlpmetrichttp/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,12 @@ func WithHeaders(headers map[string]string) Option {
return wrappedOption{oconf.WithHeaders(headers)}
}

// WithHostHeader overrides Host header in HTTP requests.
// If unset, the target Endpoint's host will be used as Host header
func WithHostHeader(host string) Option {
return wrappedOption{oconf.WithHostHeader(host)}
}

// WithTimeout sets the max amount of time an Exporter will attempt an export.
//
// This takes precedence over any retry settings defined by WithRetry. Once
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ type (
Insecure bool
TLSCfg *tls.Config
Headers map[string]string
HostHeader string
Compression Compression
Timeout time.Duration
URLPath string
Expand Down Expand Up @@ -331,6 +332,13 @@ func WithHeaders(headers map[string]string) GenericOption {
})
}

func WithHostHeader(host string) GenericOption {
return newGenericOption(func(cfg Config) Config {
cfg.Metrics.HostHeader = host
return cfg
})
}

func WithTimeout(duration time.Duration) GenericOption {
return newGenericOption(func(cfg Config) Config {
cfg.Metrics.Timeout = duration
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -197,9 +197,10 @@ func (e *HTTPResponseError) Unwrap() error { return e.Err }
type HTTPCollector struct {
plainTextResponse bool

headersMu sync.Mutex
headers http.Header
storage *Storage
headersMu sync.Mutex
headers http.Header
hostHeader string
storage *Storage

resultCh <-chan ExportResult
listener net.Listener
Expand Down Expand Up @@ -299,6 +300,10 @@ func (c *HTTPCollector) Headers() map[string][]string {
return c.headers.Clone()
}

func (c *HTTPCollector) HostHeader() string {
return c.hostHeader
}

func (c *HTTPCollector) handler(w http.ResponseWriter, r *http.Request) {
c.respond(w, c.record(r))
}
Expand Down Expand Up @@ -334,6 +339,8 @@ func (c *HTTPCollector) record(r *http.Request) ExportResult {
}
c.headersMu.Unlock()

c.hostHeader = r.Host

if c.resultCh != nil {
return <-c.resultCh
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ type (
Insecure bool
TLSCfg *tls.Config
Headers map[string]string
HostHeader string
Compression Compression
Timeout time.Duration
URLPath string
Expand Down Expand Up @@ -317,6 +318,13 @@ func WithHeaders(headers map[string]string) GenericOption {
})
}

func WithHostHeader(host string) GenericOption {
return newGenericOption(func(cfg Config) Config {
cfg.Traces.HostHeader = host
return cfg
})

Check warning on line 325 in exporters/otlp/otlptrace/otlptracegrpc/internal/otlpconfig/options.go

View check run for this annotation

Codecov / codecov/patch

exporters/otlp/otlptrace/otlptracegrpc/internal/otlpconfig/options.go#L321-L325

Added lines #L321 - L325 were not covered by tests
}

func WithTimeout(duration time.Duration) GenericOption {
return newGenericOption(func(cfg Config) Config {
cfg.Traces.Timeout = duration
Expand Down
4 changes: 4 additions & 0 deletions exporters/otlp/otlptrace/otlptracehttp/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,10 @@ func (d *client) newRequest(body []byte) (request, error) {
}
r.Header.Set("Content-Type", contentTypeProto)

if d.cfg.HostHeader != "" {
r.Host = d.cfg.HostHeader
}

req := request{Request: r}
switch Compression(d.cfg.Compression) {
case NoCompression:
Expand Down
11 changes: 11 additions & 0 deletions exporters/otlp/otlptrace/otlptracehttp/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ var (
customUserAgentHeader = map[string]string{
"user-agent": "custome-user-agent",
}

customHostName = "test-host-name"
)

func TestEndToEnd(t *testing.T) {
Expand Down Expand Up @@ -156,6 +158,15 @@ func TestEndToEnd(t *testing.T) {
ExpectedHeaders: customUserAgentHeader,
},
},
{
name: "with custom host header",
opts: []otlptracehttp.Option{
otlptracehttp.WithHostHeader(customHostName),
},
mcCfg: mockCollectorConfig{
ExpectedHostHeader: customHostName,
},
},
}

for _, tc := range tests {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.

package otlpconfig // import "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/internal/otlpconfig"
package otlpconfig

import (
"crypto/tls"
Expand Down Expand Up @@ -49,6 +49,7 @@ type (
Insecure bool
TLSCfg *tls.Config
Headers map[string]string
HostHeader string
Compression Compression
Timeout time.Duration
URLPath string
Expand Down Expand Up @@ -317,6 +318,13 @@ func WithHeaders(headers map[string]string) GenericOption {
})
}

func WithHostHeader(host string) GenericOption {
return newGenericOption(func(cfg Config) Config {
cfg.Traces.HostHeader = host
return cfg
})
}

func WithTimeout(duration time.Duration) GenericOption {
return newGenericOption(func(cfg Config) Config {
cfg.Traces.Timeout = duration
Expand Down
12 changes: 10 additions & 2 deletions exporters/otlp/otlptrace/otlptracehttp/mock_collector_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,9 @@ type mockCollector struct {
partial *collectortracepb.ExportTracePartialSuccess
delay <-chan struct{}

clientTLSConfig *tls.Config
expectedHeaders map[string]string
clientTLSConfig *tls.Config
expectedHeaders map[string]string
expectedHostHeader string
}

func (c *mockCollector) Stop() error {
Expand Down Expand Up @@ -95,6 +96,11 @@ func (c *mockCollector) serveTraces(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusBadRequest)
return
}
if c.expectedHostHeader != "" && c.expectedHostHeader != r.Host {
w.WriteHeader(http.StatusBadRequest)
return
}

response := collectortracepb.ExportTraceServiceResponse{
PartialSuccess: c.partial,
}
Expand Down Expand Up @@ -215,6 +221,7 @@ type mockCollectorConfig struct {
Delay <-chan struct{}
WithTLS bool
ExpectedHeaders map[string]string
ExpectedHostHeader string
}

func (c *mockCollectorConfig) fillInDefaults() {
Expand All @@ -238,6 +245,7 @@ func runMockCollector(t *testing.T, cfg mockCollectorConfig) *mockCollector {
partial: cfg.Partial,
delay: cfg.Delay,
expectedHeaders: cfg.ExpectedHeaders,
expectedHostHeader: cfg.ExpectedHostHeader,
}
mux := http.NewServeMux()
mux.Handle(cfg.TracesURLPath, http.HandlerFunc(m.serveTraces))
Expand Down
6 changes: 6 additions & 0 deletions exporters/otlp/otlptrace/otlptracehttp/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,12 @@ func WithHeaders(headers map[string]string) Option {
return wrappedOption{otlpconfig.WithHeaders(headers)}
}

// WithHostHeader allows one to tell the driver to override HTTP host header.
// If value is unset Endpoint's host is used as Host header.
func WithHostHeader(host string) Option {
return wrappedOption{otlpconfig.WithHostHeader(host)}
}

// WithTimeout tells the driver the max waiting time for the backend to process
// each spans batch. If unset, the default will be 10 seconds.
func WithTimeout(duration time.Duration) Option {
Expand Down
8 changes: 8 additions & 0 deletions internal/shared/otlp/otlpmetric/oconf/options.go.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ type (
Insecure bool
TLSCfg *tls.Config
Headers map[string]string
HostHeader string
Compression Compression
Timeout time.Duration
URLPath string
Expand Down Expand Up @@ -331,6 +332,13 @@ func WithHeaders(headers map[string]string) GenericOption {
})
}

func WithHostHeader(host string) GenericOption {
return newGenericOption(func(cfg Config) Config {
cfg.Metrics.HostHeader = host
return cfg
})
}

func WithTimeout(duration time.Duration) GenericOption {
return newGenericOption(func(cfg Config) Config {
cfg.Metrics.Timeout = duration
Expand Down
13 changes: 10 additions & 3 deletions internal/shared/otlp/otlpmetric/otest/collector.go.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -197,9 +197,10 @@ func (e *HTTPResponseError) Unwrap() error { return e.Err }
type HTTPCollector struct {
plainTextResponse bool

headersMu sync.Mutex
headers http.Header
storage *Storage
headersMu sync.Mutex
headers http.Header
hostHeader string
storage *Storage

resultCh <-chan ExportResult
listener net.Listener
Expand Down Expand Up @@ -299,6 +300,10 @@ func (c *HTTPCollector) Headers() map[string][]string {
return c.headers.Clone()
}

func (c *HTTPCollector) HostHeader() string {
return c.hostHeader
}

func (c *HTTPCollector) handler(w http.ResponseWriter, r *http.Request) {
c.respond(w, c.record(r))
}
Expand Down Expand Up @@ -334,6 +339,8 @@ func (c *HTTPCollector) record(r *http.Request) ExportResult {
}
c.headersMu.Unlock()

c.hostHeader = r.Host

if c.resultCh != nil {
return <-c.resultCh
}
Expand Down
Loading

0 comments on commit 99f34b3

Please sign in to comment.