Skip to content

Commit b0a52a0

Browse files
committed
Handle compressed response and follow redirects in openvsx proxy
1 parent 8ad398e commit b0a52a0

File tree

2 files changed

+68
-5
lines changed

2 files changed

+68
-5
lines changed

components/openvsx-proxy/pkg/modifyresponse.go

+35-5
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package pkg
66

77
import (
88
"bytes"
9+
"compress/gzip"
910
"fmt"
1011
"io/ioutil"
1112
"net/http"
@@ -48,19 +49,19 @@ func (o *OpenVSXProxy) ModifyResponse(r *http.Response) error {
4849
return nil
4950
}
5051

51-
body, err := ioutil.ReadAll(r.Body)
52+
rawBody, err := ioutil.ReadAll(r.Body)
5253
if err != nil {
53-
log.WithFields(logFields).WithError(err).Error("error reading response body")
54+
log.WithFields(logFields).WithError(err).Error("error reading response raw body")
5455
return err
5556
}
5657
r.Body.Close()
57-
r.Body = ioutil.NopCloser(bytes.NewBuffer(body))
58+
r.Body = ioutil.NopCloser(bytes.NewBuffer(rawBody))
5859

5960
if r.StatusCode >= 500 || r.StatusCode == http.StatusTooManyRequests || r.StatusCode == http.StatusRequestTimeout {
6061
// use cache if exists
6162
bodyLogField := "(binary)"
62-
if utf8.Valid(body) {
63-
bodyStr := string(body)
63+
if utf8.Valid(rawBody) {
64+
bodyStr := string(rawBody)
6465
truncatedSuffix := ""
6566
if len(bodyStr) > 500 {
6667
truncatedSuffix = "... [truncated]"
@@ -93,13 +94,42 @@ func (o *OpenVSXProxy) ModifyResponse(r *http.Response) error {
9394
}
9495

9596
// no error (status code < 500)
97+
body := rawBody
9698
contentType := r.Header.Get("Content-Type")
9799
if strings.HasPrefix(contentType, "application/json") {
100+
compressedResponse := strings.EqualFold(r.Header.Get("Content-Encoding"), "gzip")
101+
if compressedResponse {
102+
gzipReader, err := gzip.NewReader(ioutil.NopCloser(bytes.NewBuffer(rawBody)))
103+
if err != nil {
104+
log.WithFields(logFields).WithError(err)
105+
return nil
106+
}
107+
108+
body, err = ioutil.ReadAll(gzipReader)
109+
if err != nil {
110+
log.WithFields(logFields).WithError(err).Error("error reading compressed response body")
111+
return nil
112+
}
113+
gzipReader.Close()
114+
}
115+
98116
if log.Log.Level >= logrus.DebugLevel {
99117
log.WithFields(logFields).Debugf("replacing %d occurence(s) of '%s' in response body ...", strings.Count(string(body), o.Config.URLUpstream), o.Config.URLUpstream)
100118
}
101119
bodyStr := strings.ReplaceAll(string(body), o.Config.URLUpstream, o.Config.URLLocal)
102120
body = []byte(bodyStr)
121+
122+
if compressedResponse {
123+
var b bytes.Buffer
124+
gzipWriter := gzip.NewWriter(&b)
125+
_, err = gzipWriter.Write(body)
126+
if err != nil {
127+
log.WithFields(logFields).WithError(err).Error("error writing compressed response body")
128+
return nil
129+
}
130+
gzipWriter.Close()
131+
body = b.Bytes()
132+
}
103133
} else {
104134
log.WithFields(logFields).Debugf("response is not JSON but '%s', skipping replacing '%s' in response body", contentType, o.Config.URLUpstream)
105135
}

components/openvsx-proxy/pkg/openvsxproxy_test.go

+33
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package pkg
66

77
import (
88
"bytes"
9+
"compress/gzip"
910
"fmt"
1011
"io"
1112
"net/http"
@@ -55,6 +56,38 @@ func TestReplaceHostInJSONResponse(t *testing.T) {
5556
}
5657
}
5758

59+
func TestReplaceHostInCompressedJSONResponse(t *testing.T) {
60+
backend := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
61+
bodyBytes, _ := io.ReadAll(r.Body)
62+
rw.Header().Set("Content-Type", "application/json")
63+
rw.Header().Set("Content-Encoding", "gzip")
64+
65+
var b bytes.Buffer
66+
w := gzip.NewWriter(&b)
67+
w.Write([]byte(fmt.Sprintf("Hello %s!", string(bodyBytes))))
68+
w.Close()
69+
rw.Write(b.Bytes())
70+
}))
71+
defer backend.Close()
72+
73+
frontend, _ := createFrontend(backend.URL)
74+
defer frontend.Close()
75+
76+
frontendClient := frontend.Client()
77+
78+
requestBody := backend.URL
79+
req, _ := http.NewRequest("POST", frontend.URL, bytes.NewBuffer([]byte(requestBody)))
80+
req.Close = true
81+
res, err := frontendClient.Do(req)
82+
if err != nil {
83+
t.Fatal(err)
84+
}
85+
expectedResponse := fmt.Sprintf("Hello %s!", frontend.URL)
86+
if bodyBytes, _ := io.ReadAll(res.Body); string(bodyBytes) != expectedResponse {
87+
t.Errorf("got body '%s'; expected '%s'", string(bodyBytes), expectedResponse)
88+
}
89+
}
90+
5891
func TestNotReplaceHostInNonJSONResponse(t *testing.T) {
5992
backend := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
6093
bodyBytes, _ := io.ReadAll(r.Body)

0 commit comments

Comments
 (0)