diff --git a/.changes/unreleased/BUG FIXES-20240719-143606.yaml b/.changes/unreleased/BUG FIXES-20240719-143606.yaml new file mode 100644 index 00000000..e3ddbc9b --- /dev/null +++ b/.changes/unreleased/BUG FIXES-20240719-143606.yaml @@ -0,0 +1,5 @@ +kind: BUG FIXES +body: 'data-source/http: Allow `Host` header in `request_headers` to be set on HTTP request' +time: 2024-07-19T14:36:06.795798-04:00 +custom: + Issue: "440" diff --git a/.changes/unreleased/NOTES-20240723-162543.yaml b/.changes/unreleased/NOTES-20240723-162543.yaml new file mode 100644 index 00000000..b9029ce0 --- /dev/null +++ b/.changes/unreleased/NOTES-20240723-162543.yaml @@ -0,0 +1,17 @@ +kind: NOTES +body: |+ + data-source/http: Previous versions of this provider ignored any `Host` headers specified in the `request_headers` attribute when setting the HTTP request. Any specified `Host` request headers will now override the `url` attribute host. + + For example, in the following configuration: + ```hcl + data "http" "example" { + url = "https://www.example.com" + request_headers = { + Host = "www.differentexample.com" + } + } + ``` + The HTTP request host will now be `www.differentexample.com` instead of `www.example.com`. +time: 2024-07-23T16:25:43.160519-04:00 +custom: + Issue: "440" diff --git a/internal/provider/data_source_http.go b/internal/provider/data_source_http.go index f6cb5508..ee81b9d6 100644 --- a/internal/provider/data_source_http.go +++ b/internal/provider/data_source_http.go @@ -315,6 +315,9 @@ func (d *httpDataSource) Read(ctx context.Context, req datasource.ReadRequest, r } request.Header.Set(name, header) + if name == "Host" { + request.Host = header + } } response, err := retryClient.Do(request) diff --git a/internal/provider/data_source_http_test.go b/internal/provider/data_source_http_test.go index d10dde53..8ef7fc70 100644 --- a/internal/provider/data_source_http_test.go +++ b/internal/provider/data_source_http_test.go @@ -602,6 +602,49 @@ func TestDataSource_UnsupportedInsecureCaCert(t *testing.T) { }) } +func TestDataSource_HostRequestHeaderOverride_200(t *testing.T) { + altHost := "alt-test-host" + + testServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.Host != altHost { + w.WriteHeader(400) + return + } + + w.Header().Set("Content-Type", "text/plain") + w.Header().Set("X-Single", "foobar") + w.Header().Add("X-Double", "1") + w.Header().Add("X-Double", "2") + _, err := w.Write([]byte("1.0.0")) + if err != nil { + t.Errorf("error writing body: %s", err) + } + })) + defer testServer.Close() + + resource.ParallelTest(t, resource.TestCase{ + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Steps: []resource.TestStep{ + { + Config: fmt.Sprintf(` + data "http" "http_test" { + url = "%s" + request_headers = { + "Host" = "%s" + } + }`, testServer.URL, altHost), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.http.http_test", "status_code", "200"), + resource.TestCheckResourceAttr("data.http.http_test", "response_body", "1.0.0"), + resource.TestCheckResourceAttr("data.http.http_test", "response_headers.Content-Type", "text/plain"), + resource.TestCheckResourceAttr("data.http.http_test", "response_headers.X-Single", "foobar"), + resource.TestCheckResourceAttr("data.http.http_test", "response_headers.X-Double", "1, 2"), + ), + }, + }, + }) +} + // testProxiedURL is a hardcoded URL used in acceptance testing where it is // expected that a locally started HTTP proxy will handle the request. //