cloudevents/sdk-go

Unable to set Host header on Client

jaxtonw opened this issue · 1 comments

Bug

Due to the way GoLang represents the Host header in an HTTP request--promoting it to an attribute of the request instead of treating it as another header--there is no way to manually set the Host header using the WithHeader option.

When making a request, we already check the RequestTemplate for the Host attribute. However, there is no way to set this attribute.

req.Host = p.RequestTemplate.Host

Workaround

One workaround is to directly access the RequestTemplate and set the host:

p, err = cloudevents.NewHTTP(cloudevents.WithTarget(sink))
if p.RequestTemplate != nil {
	p.RequestTemplate.Host = "different.host"
}

However, this is not properly documented and not a clean or native solution.

Possible Solution

Given that we already have the capability to customize the Host header that gets sent with the request template, we can address it with the following solutions:

  1. Modify the WithHeader Option to see if the set Header is Host, and assign that value to RequestTemplate.Host
  2. Create a new Option, WithHost(value string) Option which sets RequestTemplate.Host to the provided value

Mock Implementation Of #1

// WithHeader sets an additional default outbound header for all cloudevents
// when using an HTTP request.
func WithHeader(key, value string) Option {
	return func(p *Protocol) error {
		if p == nil {
			return fmt.Errorf("http header option can not set nil protocol")
		}
		key = strings.TrimSpace(key)
		if key != "" {
			if p.RequestTemplate == nil {
				p.RequestTemplate = &nethttp.Request{
					Method: nethttp.MethodPost,
				}
			}
			if strings.ToLower(key) == "host" {
				p.RequestTemplate.Host = value
				return nil
			}
			if p.RequestTemplate.Header == nil {
				p.RequestTemplate.Header = nethttp.Header{}
			}
			p.RequestTemplate.Header.Add(key, value)
			return nil
		}
		return fmt.Errorf("http header option was empty string")
	}
}

Mock Implementation Of #2

// WithHost sets the outbound host header for all cloud events when using an HTTP request
func WithHost(value string) Option {
	return func(p *Protocol) error {
		if p == nil {
			return fmt.Errorf("http header option can not set nil protocol")
		}
		value = strings.TrimSpace(value)
		if value != "" {
			if p.RequestTemplate == nil {
				p.RequestTemplate = &nethttp.Request{
					Method: nethttp.MethodPost,
				}
			}
			p.RequestTemplate.Host = value
			return nil
		}
		return fmt.Errorf("http host option was empty string")
	}
}

Issue has been resolved with PR #1070. Planned to be in the next release.