Streaming responses to a client: possible?

59 views
Skip to first unread message

Siddharth Mathur

unread,
Mar 1, 2015, 5:10:37 AM3/1/15
to gopro...@googlegroups.com
Hi Elazar and others,

Any tips on how to stream a response to a client? Specifically, once I have an HTML response within GoProxy from the origin server, I would like to start sending partial modified HTML content to the client (say a browser) as soon as I have something ready. Currently the API only supports sending a fully formed http.Response object. Is my interpretation correct? 
FuncRespHandler(func(resp *http.Response, ctx *ProxyCtx) *http.Response


In proxy.go, we appear to process all the filters installed, and then do a memcopy into a actual response sent to the client. Seems I can't be writing to a HttpResponseWriter  in one of my RespHandlers and doing a Flush() when the situation demands ? Or is there a way that I am missing? :) 

         resp = proxy.filterResponse(resp, ctx)

ctx.Logf("Copying response to client %v [%d]", resp.Status, resp.StatusCode)
if origBody != resp.Body {
resp.Header.Del("Content-Length")
}
copyHeaders(w.Header(), resp.Header)
w.WriteHeader(resp.StatusCode)
nr, err := io.Copy(w, resp.Body)
if err := resp.Body.Close(); err != nil {
ctx.Warnf("Can't close response body %v", err)
}


Thanks much!
Siddharth

Elazar Leibovich

unread,
Mar 1, 2015, 5:42:20 AM3/1/15
to Siddharth Mathur, gopro...@googlegroups.com
Hi,

What you should do, is to create an http.Response object whose body is a streaming writer.

This is not ideal, and we should support creating http responses easily through goproxy. I need to think through what's the best way to expose that through the API.

For example:

package main

import (
"flag"
"io"
"log"
"net/http"
"time"

)

func main() {
addr := flag.String("addr", ":8080", "proxy listen address")
flag.Parse()
proxy := goproxy.NewProxyHttpServer()
proxy.Verbose = true
proxy.OnRequest().DoFunc(func(req *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) {
resp := goproxy.NewResponse(req, "text/plain", http.StatusAccepted, "")
resp.ContentLength = -1
//resp.TransferEncoding = []string{"chunked"}
pr, pw := io.Pipe()
go func() {
io.WriteString(pw, "hello\n")
io.WriteString(pw, "world\n")
for i := 0; i < 10; i++ {
for j := 0; j < 100; j++ {
io.WriteString(pw, "1234567890")
}
io.WriteString(pw, "\n")
time.Sleep(1 * time.Second)
log.Println("sleeping", i)
}
pw.Close()
}()
resp.Body = pr
println("RETURNING")
return nil, resp
})
log.Fatal(http.ListenAndServe(*addr, proxy))
}


--
You received this message because you are subscribed to the Google Groups "goproxy-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to goproxy-dev...@googlegroups.com.
To post to this group, send email to gopro...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/goproxy-dev/0c2d3bb5-44b2-45a2-a378-257d5727f04b%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Siddharth Mathur

unread,
Mar 1, 2015, 6:19:01 AM3/1/15
to Elazar Leibovich, gopro...@googlegroups.com
Thanks much Elazar, using a PipeReader and PipeWriter would certainly do the trick! Great stuff. 

For the same use case, how would implement the ability to flush the partial response down the network pipe? 

Thanks much for your time and software.
Siddharth
Reply all
Reply to author
Forward
0 new messages