Skip to content
This repository has been archived by the owner on Jul 5, 2022. It is now read-only.

Commit

Permalink
fix bugs when transfer chunked result
Browse files Browse the repository at this point in the history
  • Loading branch information
nyanpassu committed Sep 2, 2021
1 parent 5b37b64 commit 2ad4f77
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 0 deletions.
5 changes: 5 additions & 0 deletions proxy/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@ func (ph HTTPProxyHandler) proxy(response http.ResponseWriter, request *http.Req
return
}
if resp.StatusCode != http.StatusSwitchingProtocols {
if request.Method == http.MethodGet && utils.IsChunkedEncoding(resp) {
log.Debug("[dispatch] Forward chunked response")
utils.ForwardChunked(response, resp)
return
}
log.Debug("[dispatch] Forward http response")
if err := utils.Forward(resp, response); err != nil {
log.Errorf("[dispatch] forward docker socket response failed %v", err)
Expand Down
74 changes: 74 additions & 0 deletions utils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,80 @@ func Initialize(bufSize int) {
debug = log.GetLevel() == log.DebugLevel
}

func IsChunkedEncoding(src *http.Response) bool {
for _, value := range src.TransferEncoding {
if lower := strings.ToLower(strings.Trim(value, " ")); lower == "chunked" {
return true
}
}
return false
}

func ForwardChunked(response http.ResponseWriter, resp *http.Response) {
log.Info("[ForwardChunked] Will forward chunked response")
initResponseHeader(response, resp.StatusCode, resp.Header)

buffer := make([]byte, 256)
for {
cnt, err := resp.Body.Read(buffer)
readed := buffer[:cnt]

log.Infof("%d bytes readed", cnt)

if _, err := response.Write(readed); err != nil {
log.WithError(err).Error("server response write error")
return
}
if flusher, ok := response.(http.Flusher); ok {
flusher.Flush()
} else {
log.Warn("[proxyHttp] server response is not http flusher")
}

if err == io.EOF {
log.Info("[doForwardChunked] client response end")
return
}

if err != nil {
log.WithError(err).Error("copy io error")
return
}
}

// link client conn and server conn
log.Info("[doForwardChunked] completed")
}

func forwardChunked(client io.ReadWriteCloser, server io.ReadCloser) {
log.Info("[forwardChunked] Starting forward chunked stream")

if _, err := io.Copy(client, server); err != nil {
if err == io.EOF {
log.Info("[forwardChunked] forwardChunked encounter EOF")
return
}
log.Errorf("[forwardChunked] forwardChunked end with %v", err)
}
log.Infof("[forwardChunked] End forward chunked stream")
}

func initResponseHeader(response http.ResponseWriter, statusCode int, header http.Header) {
PrintHeaders("ServerResponse", header)
responseHeader := response.Header()
for key, values := range header {
for _, value := range values {
responseHeader.Add(key, value)
}
}
response.WriteHeader(statusCode)
if flusher, ok := response.(http.Flusher); ok {
flusher.Flush()
} else {
log.Error("[WriteToServerResponse] Can't make flush to http.flusher")
}
}

// Forward .
func Forward(src *http.Response, dst http.ResponseWriter) error {
copyHeader(src, dst)
Expand Down

0 comments on commit 2ad4f77

Please sign in to comment.