-
Notifications
You must be signed in to change notification settings - Fork 118
/
data_source.go
138 lines (113 loc) · 3.31 KB
/
data_source.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
package provider
import (
"context"
"fmt"
"io/ioutil"
"mime"
"net/http"
"regexp"
"strings"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)
func dataSource() *schema.Resource {
return &schema.Resource{
ReadContext: dataSourceRead,
Schema: map[string]*schema.Schema{
"url": {
Type: schema.TypeString,
Required: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
"request_headers": {
Type: schema.TypeMap,
Optional: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
"body": {
Type: schema.TypeString,
Computed: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
"response_headers": {
Type: schema.TypeMap,
Computed: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
},
}
}
func dataSourceRead(ctx context.Context, d *schema.ResourceData, meta interface{}) (diags diag.Diagnostics) {
url := d.Get("url").(string)
headers := d.Get("request_headers").(map[string]interface{})
client := &http.Client{}
req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
if err != nil {
return append(diags, diag.Errorf("Error creating request: %s", err)...)
}
for name, value := range headers {
req.Header.Set(name, value.(string))
}
resp, err := client.Do(req)
if err != nil {
return append(diags, diag.Errorf("Error making request: %s", err)...)
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
return append(diags, diag.Errorf("HTTP request error. Response code: %d", resp.StatusCode)...)
}
contentType := resp.Header.Get("Content-Type")
if contentType == "" || isContentTypeText(contentType) == false {
diags = append(diags, diag.Diagnostic{
Severity: diag.Warning,
Summary: fmt.Sprintf("Content-Type is not recognized as a text type, got %q", contentType),
Detail: "If the content is binary data, Terraform may not properly handle the contents of the response.",
})
}
bytes, err := ioutil.ReadAll(resp.Body)
if err != nil {
return append(diags, diag.FromErr(err)...)
}
responseHeaders := make(map[string]string)
for k, v := range resp.Header {
// Concatenate according to RFC2616
// cf. https://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2
responseHeaders[k] = strings.Join(v, ", ")
}
d.Set("body", string(bytes))
if err = d.Set("response_headers", responseHeaders); err != nil {
return append(diags, diag.Errorf("Error setting HTTP response headers: %s", err)...)
}
// set ID as something more stable than time
d.SetId(url)
return diags
}
// This is to prevent potential issues w/ binary files
// and generally unprintable characters
// See https://github.com/hashicorp/terraform/pull/3858#issuecomment-156856738
func isContentTypeText(contentType string) bool {
parsedType, params, err := mime.ParseMediaType(contentType)
if err != nil {
return false
}
allowedContentTypes := []*regexp.Regexp{
regexp.MustCompile("^text/.+"),
regexp.MustCompile("^application/json$"),
regexp.MustCompile("^application/samlmetadata\\+xml"),
}
for _, r := range allowedContentTypes {
if r.MatchString(parsedType) {
charset := strings.ToLower(params["charset"])
return charset == "" || charset == "utf-8" || charset == "us-ascii"
}
}
return false
}