forked from jasonwbarnett/terraform-registry-proxy
-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.go
147 lines (127 loc) · 3.93 KB
/
main.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
139
140
141
142
143
144
145
146
147
package main
import (
"bytes"
"compress/gzip"
"flag"
"fmt"
"io"
"io/ioutil"
"net/http"
"net/http/httputil"
"net/url"
"os"
"strconv"
"strings"
"github.com/gorilla/handlers"
)
// WebReverseProxyConfiguration is a coniguration for the ReverseProxy
type WebReverseProxyConfiguration struct {
RegistryProxyHost string
ReleaseProxyHost string
ReleasePathPrefix string
}
var (
registryHost string
releaseHost string
releasePathPrefix string
httpAddress string
)
func init() {
flag.StringVar(®istryHost, "registry-proxy-host", "", "FQDN of registry proxy host [Required]")
flag.StringVar(&releaseHost, "release-proxy-host", "", "FQDN of release proxy host [Required]")
flag.StringVar(&releasePathPrefix, "release-proxy-path-prefix", "", "The prefix path to prepend to any release artifact paths. This might be /artifactory/hashicorp-releases")
flag.StringVar(&httpAddress, "http-address", ":8555", "HTTP address to listen on, e.g. :8080 or 127.0.0.1:8080")
flag.Parse()
if registryHost == "" {
fmt.Printf("You must provide a -registry-proxy-host value\n\n")
flag.Usage()
os.Exit(1)
}
if releaseHost == "" {
fmt.Printf("You must provide a -release-proxy-host value\n\n")
flag.Usage()
os.Exit(1)
}
}
func main() {
config := &WebReverseProxyConfiguration{
RegistryProxyHost: registryHost,
ReleaseProxyHost: releaseHost,
ReleasePathPrefix: releasePathPrefix,
}
proxy := config.NewWebReverseProxy()
http.Handle("/", handlers.LoggingHandler(os.Stdout, proxy))
// Start the server
http.ListenAndServe(httpAddress, nil)
}
// This replaces all occurrences of http://releases.hashicorp.com with
// config.ReleaseProxyHost in the response body
func (config *WebReverseProxyConfiguration) rewriteBody(resp *http.Response) (err error) {
// Check that the server actually sent compressed data
var reader io.ReadCloser
switch resp.Header.Get("Content-Encoding") {
case "gzip":
reader, err = gzip.NewReader(resp.Body)
resp.Header.Del("Content-Encoding")
resp.Header.Del("Content-Length")
resp.ContentLength = -1
resp.Uncompressed = true
defer reader.Close()
default:
reader = resp.Body
}
b, err := ioutil.ReadAll(reader)
if err != nil {
return err
}
if err = resp.Body.Close(); err != nil {
return err
}
replacement := fmt.Sprintf("https://%s%s", config.ReleaseProxyHost, config.ReleasePathPrefix)
b = bytes.ReplaceAll(b, []byte("https://releases.hashicorp.com"), []byte(replacement)) // releases
body := ioutil.NopCloser(bytes.NewReader(b))
resp.Body = body
resp.ContentLength = int64(len(b))
resp.Header.Set("Content-Length", strconv.Itoa(len(b)))
return nil
}
func (config *WebReverseProxyConfiguration) NewWebReverseProxy() *httputil.ReverseProxy {
director := func(req *http.Request) {
if req.Host == config.RegistryProxyHost {
req.URL.Scheme = "https"
req.URL.Host = "registry.terraform.io"
req.Host = "registry.terraform.io"
req.Header.Set("User-Agent", "Terraform/1.1.7")
req.Header.Set("X-Terraform-Version", "1.1.7")
} else if req.Host == config.ReleaseProxyHost {
req.URL.Scheme = "https"
req.URL.Host = "releases.hashicorp.com"
req.Host = "releases.hashicorp.com"
req.Header.Set("User-Agent", "Terraform/1.1.7")
}
}
responseDirector := func(res *http.Response) error {
if server := res.Header.Get("Server"); strings.HasPrefix(server, "terraform-registry") {
if err := config.rewriteBody(res); err != nil {
fmt.Println("Error rewriting body!")
return err
}
}
if location := res.Header.Get("Location"); location != "" {
url, err := url.ParseRequestURI(location)
if err != nil {
fmt.Println("Error!")
return err
}
// Override redirect url Host with ProxyHost
url.Host = config.RegistryProxyHost
res.Header.Set("Location", url.String())
res.Header.Set("X-Reverse-Proxy", "terraform-registry-proxy")
}
return nil
}
return &httputil.ReverseProxy{
Director: director,
ModifyResponse: responseDirector,
}
}