Skip to content

Commit b6faa9c

Browse files
authored
Merge pull request #1 from sktan/npm_fix
NPM Fix
2 parents a284010 + 1d19f9c commit b6faa9c

1 file changed

Lines changed: 73 additions & 0 deletions

File tree

src/tools/proxy.go

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,34 @@
11
package tools
22

33
import (
4+
"compress/gzip"
5+
"fmt"
6+
"io"
7+
"io/ioutil"
48
"log"
59
"net/http"
610
"net/http/httputil"
711
"net/url"
12+
"strconv"
813
"strings"
914
)
1015

16+
var originalUrlResolver = make(map[string]*url.URL)
17+
1118
// ProxyRequestHandler intercepts requests to CodeArtifact and add the Authorization header + correct Host header
1219
func ProxyRequestHandler(p *httputil.ReverseProxy) func(http.ResponseWriter, *http.Request) {
1320
return func(w http.ResponseWriter, r *http.Request) {
21+
// Store the original host header for each request
22+
originalUrlResolver[r.RemoteAddr] = r.URL
23+
originalUrlResolver[r.RemoteAddr].Host = r.Host
24+
originalUrlResolver[r.RemoteAddr].Scheme = r.URL.Scheme
25+
26+
if r.Header.Get("X-Forwarded-Proto") == "https" {
27+
originalUrlResolver[r.RemoteAddr].Scheme = "https"
28+
} else {
29+
originalUrlResolver[r.RemoteAddr].Scheme = "http"
30+
}
31+
1432
// Override the Host header with the CodeArtifact Host
1533
u, _ := url.Parse(CodeArtifactAuthInfo.Url)
1634
r.Host = u.Host
@@ -28,10 +46,65 @@ func ProxyRequestHandler(p *httputil.ReverseProxy) func(http.ResponseWriter, *ht
2846

2947
func ProxyResponseHandler() func(*http.Response) error {
3048
return func(r *http.Response) error {
49+
log.Printf("Received response from %s", r.Request.URL.String())
3150
log.Printf("RES: %s \"%s\" %d \"%s\" \"%s\"", r.Request.RemoteAddr, r.Request.Method, r.StatusCode, r.Request.RequestURI, r.Request.UserAgent())
3251

52+
contentType := r.Header.Get("Content-Type")
53+
54+
originalUrl := originalUrlResolver[r.Request.RemoteAddr]
55+
delete(originalUrlResolver, r.Request.RemoteAddr)
56+
57+
u, _ := url.Parse(CodeArtifactAuthInfo.Url)
58+
hostname := u.Host + ":443"
59+
60+
// Rewrite the 301 to point from CodeArtifact URL to the proxy instead..
61+
if r.StatusCode == 301 || r.StatusCode == 302 {
62+
location, _ := r.Location()
63+
64+
location.Host = originalUrl.Host
65+
location.Scheme = originalUrl.Scheme
66+
location.Path = strings.Replace(location.Path, u.Path, "", 1)
67+
68+
r.Header.Set("Location", location.String())
69+
}
70+
71+
// Do some quick fixes to the HTTP response for NPM install requests
72+
// TODO: Get this actually working, it looks like the JSON responses provide the correct URLs via CURL, but not when using npm against it.
73+
if strings.HasPrefix(r.Request.UserAgent(), "npm") {
74+
75+
// Respond to only requests that respond with JSON
76+
// There might eventually be additional headers i don't know about?
77+
if !strings.Contains(contentType, "application/json") && !strings.Contains(contentType, "application/vnd.npm.install-v1+json") {
78+
return nil
79+
}
80+
81+
var body io.ReadCloser
82+
83+
if r.Header.Get("Content-Encoding") == "gzip" {
84+
body, _ = gzip.NewReader(r.Body)
85+
r.Header.Del("Content-Encoding")
86+
} else {
87+
body = r.Body
88+
}
89+
90+
// replace any instances of the CodeArtifact URL with the local URL
91+
oldContentResponse, _ := ioutil.ReadAll(body)
92+
oldContentResponseStr := string(oldContentResponse)
93+
94+
resolvedHostname := strings.Replace(CodeArtifactAuthInfo.Url, u.Host, hostname, -1)
95+
newUrl := fmt.Sprintf("%s://%s/", originalUrl.Scheme, originalUrl.Host)
96+
97+
newResponseContent := strings.Replace(oldContentResponseStr, resolvedHostname, newUrl, -1)
98+
newResponseContent = strings.Replace(newResponseContent, CodeArtifactAuthInfo.Url, newUrl, -1)
99+
100+
r.Body = ioutil.NopCloser(strings.NewReader(newResponseContent))
101+
r.ContentLength = int64(len(newResponseContent))
102+
r.Header.Set("Content-Length", strconv.Itoa(len(newResponseContent)))
103+
}
104+
33105
return nil
34106
}
107+
35108
}
36109

37110
// ProxyInit initialises the CodeArtifact proxy and starts the HTTP listener

0 commit comments

Comments
 (0)