diff --git a/res_handler_transform.go b/res_handler_transform.go index 6a18fba8a68..4ffb47073bd 100644 --- a/res_handler_transform.go +++ b/res_handler_transform.go @@ -2,7 +2,10 @@ package main import ( "bytes" + "compress/flate" + "compress/gzip" "encoding/json" + "io" "io/ioutil" "net/http" "strconv" @@ -23,6 +26,43 @@ func (h *ResponseTransformMiddleware) Init(c interface{}, spec *APISpec) error { return nil } +func respBodyReader(req *http.Request, resp *http.Response) io.ReadCloser { + if req.Header.Get("Accept-Encoding") == "" { + return resp.Body + } + + switch resp.Header.Get("Content-Encoding") { + case "gzip": + reader, err := gzip.NewReader(resp.Body) + if err != nil { + log.Error("Body decompression error:", err) + return ioutil.NopCloser(bytes.NewReader(nil)) + } + return reader + case "deflate": + return flate.NewReader(resp.Body) + } + + return resp.Body +} + +func compressBuffer(in bytes.Buffer, encoding string) (out bytes.Buffer) { + switch encoding { + case "gzip": + zw := gzip.NewWriter(&out) + zw.Write(in.Bytes()) + zw.Close() + case "deflate": + zw, _ := flate.NewWriter(&out, 1) + zw.Write(in.Bytes()) + zw.Close() + default: + out = in + } + + return out +} + func (h *ResponseTransformMiddleware) HandleResponse(rw http.ResponseWriter, res *http.Response, req *http.Request, ses *user.SessionState) error { _, versionPaths, _, _ := h.Spec.Version(req) found, meta := h.Spec.CheckSpecMatchesStatus(req, versionPaths, TransformedResponse) @@ -32,8 +72,8 @@ func (h *ResponseTransformMiddleware) HandleResponse(rw http.ResponseWriter, res } tmeta := meta.(*TransformSpec) - // Read the body: - defer res.Body.Close() + respBody := respBodyReader(req, res) + defer respBody.Close() // Put into an interface: var bodyData map[string]interface{} @@ -41,7 +81,11 @@ func (h *ResponseTransformMiddleware) HandleResponse(rw http.ResponseWriter, res case apidef.RequestXML: mxj.XmlCharsetReader = WrappedCharsetReader var err error - bodyData, err = mxj.NewMapXmlReader(res.Body) // unmarshal + + bodyBuf, _ := ioutil.ReadAll(respBody) + log.Warning("BODY:", string(bodyBuf)) + + bodyData, err = mxj.NewMapXml(bodyBuf) // unmarshal if err != nil { log.WithFields(logrus.Fields{ "prefix": "outbound-transform", @@ -51,7 +95,7 @@ func (h *ResponseTransformMiddleware) HandleResponse(rw http.ResponseWriter, res }).Error("Error unmarshalling XML: ", err) } default: // apidef.RequestJSON - if err := json.NewDecoder(res.Body).Decode(&bodyData); err != nil { + if err := json.NewDecoder(respBody).Decode(&bodyData); err != nil { log.WithFields(logrus.Fields{ "prefix": "outbound-transform", "server_name": h.Spec.Proxy.TargetURL, @@ -72,6 +116,10 @@ func (h *ResponseTransformMiddleware) HandleResponse(rw http.ResponseWriter, res }).Error("Failed to apply template to request: ", err) } + // Re-compress if original upstream response was compressed + encoding := res.Header.Get("Content-Encoding") + bodyBuffer = compressBuffer(bodyBuffer, encoding) + res.ContentLength = int64(bodyBuffer.Len()) res.Header.Set("Content-Length", strconv.Itoa(bodyBuffer.Len())) res.Body = ioutil.NopCloser(&bodyBuffer)