Skip to content

Commit 1d19f9c

Browse files
committed
Fixed NPM support
1 parent 9ee2350 commit 1d19f9c

1 file changed

Lines changed: 48 additions & 9 deletions

File tree

src/tools/proxy.go

Lines changed: 48 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package tools
22

33
import (
4+
"compress/gzip"
45
"fmt"
6+
"io"
57
"io/ioutil"
68
"log"
79
"net/http"
@@ -11,9 +13,22 @@ import (
1113
"strings"
1214
)
1315

16+
var originalUrlResolver = make(map[string]*url.URL)
17+
1418
// ProxyRequestHandler intercepts requests to CodeArtifact and add the Authorization header + correct Host header
1519
func ProxyRequestHandler(p *httputil.ReverseProxy) func(http.ResponseWriter, *http.Request) {
1620
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+
1732
// Override the Host header with the CodeArtifact Host
1833
u, _ := url.Parse(CodeArtifactAuthInfo.Url)
1934
r.Host = u.Host
@@ -31,33 +46,57 @@ func ProxyRequestHandler(p *httputil.ReverseProxy) func(http.ResponseWriter, *ht
3146

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

3652
contentType := r.Header.Get("Content-Type")
37-
log.Printf("%s", contentType)
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+
}
3870

3971
// Do some quick fixes to the HTTP response for NPM install requests
4072
// TODO: Get this actually working, it looks like the JSON responses provide the correct URLs via CURL, but not when using npm against it.
4173
if strings.HasPrefix(r.Request.UserAgent(), "npm") {
42-
if !strings.Contains(contentType, "application/json") {
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") {
4378
return nil
4479
}
4580

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+
4690
// replace any instances of the CodeArtifact URL with the local URL
47-
oldContentResponse, _ := ioutil.ReadAll(r.Body)
91+
oldContentResponse, _ := ioutil.ReadAll(body)
4892
oldContentResponseStr := string(oldContentResponse)
4993

50-
u, _ := url.Parse(CodeArtifactAuthInfo.Url)
51-
hostname := u.Host + ":443"
52-
5394
resolvedHostname := strings.Replace(CodeArtifactAuthInfo.Url, u.Host, hostname, -1)
54-
newUrl := fmt.Sprintf("http://%s/", "localhost")
95+
newUrl := fmt.Sprintf("%s://%s/", originalUrl.Scheme, originalUrl.Host)
5596

5697
newResponseContent := strings.Replace(oldContentResponseStr, resolvedHostname, newUrl, -1)
5798
newResponseContent = strings.Replace(newResponseContent, CodeArtifactAuthInfo.Url, newUrl, -1)
5899

59-
log.Print(newResponseContent)
60-
61100
r.Body = ioutil.NopCloser(strings.NewReader(newResponseContent))
62101
r.ContentLength = int64(len(newResponseContent))
63102
r.Header.Set("Content-Length", strconv.Itoa(len(newResponseContent)))

0 commit comments

Comments
 (0)