func TestGoproxyThroughProxy(t *testing.T) { proxy := goproxy.NewProxyHttpServer() proxy2 := goproxy.NewProxyHttpServer() doubleString := goproxy.HandlerFunc(func(ctx *goproxy.ProxyCtx) goproxy.Next { resp := ctx.Resp b, err := ioutil.ReadAll(resp.Body) panicOnErr(err, "readAll resp") resp.Body = ioutil.NopCloser(bytes.NewBufferString(string(b) + " " + string(b))) return goproxy.NEXT }) proxy.HandleConnect(goproxy.AlwaysMitm) proxy.HandleResponse(doubleString) _, l := oneShotProxy(proxy, t) defer l.Close() proxy2.ConnectDial = proxy2.NewConnectDialToProxy(l.URL) client, l2 := oneShotProxy(proxy2, t) defer l2.Close() if r := string(getOrFail(https.URL+"/bobo", client, t)); r != "bobo bobo" { t.Error("Expected bobo doubled twice, got", r) } }
func TestCurlMinusP(t *testing.T) { proxy := goproxy.NewProxyHttpServer() proxy.HandleConnectFunc(func(ctx *goproxy.ProxyCtx) goproxy.Next { return goproxy.MITM // default host }) called := false proxy.HandleRequestFunc(func(ctx *goproxy.ProxyCtx) goproxy.Next { called = true return goproxy.NEXT }) _, l := oneShotProxy(proxy, t) defer l.Close() cmd := exec.Command("curl", "-p", "-sS", "--proxy", l.URL, srv.URL+"/bobo") output, err := cmd.CombinedOutput() if err != nil { t.Fatal(err) } if string(output) != "bobo" { t.Error("Expected bobo, got", string(output)) } if !called { t.Error("handler not called") } }
func TestReplaceImage(t *testing.T) { proxy := goproxy.NewProxyHttpServer() panda := getImage("test_data/panda.png", t) football := getImage("test_data/football.png", t) proxy.HandleResponse(goproxy.UrlIsIn("/test_data/panda.png")(goproxy_image.HandleImage(func(img image.Image, ctx *goproxy.ProxyCtx) image.Image { return football }))) proxy.HandleResponse(goproxy.UrlIsIn("/test_data/football.png")(goproxy_image.HandleImage(func(img image.Image, ctx *goproxy.ProxyCtx) image.Image { return panda }))) client, l := oneShotProxy(proxy, t) defer l.Close() imgByPandaReq, _, err := image.Decode(bytes.NewReader(getOrFail(localFile("test_data/panda.png"), client, t))) fatalOnErr(err, "decode panda", t) compareImage(football, imgByPandaReq, t) imgByFootballReq, _, err := image.Decode(bytes.NewReader(getOrFail(localFile("test_data/football.png"), client, t))) fatalOnErr(err, "decode football", t) compareImage(panda, imgByFootballReq, t) }
func main() { proxy := goproxy.NewProxyHttpServer() timer := make(chan bool) ch := make(chan Count, 10) go func() { for { time.Sleep(20 * time.Second) timer <- true } }() go func() { m := make(map[string]int64) for { select { case c := <-ch: m[c.Id] = m[c.Id] + c.Count case <-timer: fmt.Printf("statistics\n") for k, v := range m { fmt.Printf("%s -> %d\n", k, v) } } } }() // IsWebRelatedText filters on html/javascript/css resources proxy.OnResponse(goproxy_html.IsWebRelatedText).DoFunc(func(resp *Response, ctx *goproxy.ProxyCtx) *Response { resp.Body = &CountReadCloser{ctx.Req.URL.String(), resp.Body, ch, 0} return resp }) fmt.Printf("listening on :8080\n") log.Fatal(proxy.ListenAndServe(":8080")) }
func TestContentType(t *testing.T) { proxy := goproxy.NewProxyHttpServer() mangleImage := goproxy.HandlerFunc(func(ctx *goproxy.ProxyCtx) goproxy.Next { ctx.Resp.Header.Set("X-Shmoopi", "1") return goproxy.NEXT }) proxy.HandleResponse(goproxy.RespContentTypeIs("image/png")(mangleImage)) client, l := oneShotProxy(proxy, t) defer l.Close() for _, file := range []string{"test_data/panda.png", "test_data/football.png"} { if resp, err := client.Get(localFile(file)); err != nil || resp.Header.Get("X-Shmoopi") != "1" { if err == nil { t.Error("pngs should have X-Shmoopi header = 1, actually", resp.Header.Get("X-Shmoopi")) } else { t.Error("error reading png", err) } } } file := "baby.jpg" if resp, err := client.Get(localFile(file)); err != nil || resp.Header.Get("X-Shmoopi") != "" { if err == nil { t.Error("Non png images should NOT have X-Shmoopi header at all", resp.Header.Get("X-Shmoopi")) } else { t.Error("error reading png", err) } } }
func TestWithBrowser(t *testing.T) { // an easy way to check if auth works with webserver // to test, run with // $ go test -run TestWithBrowser -- server // configure a browser to use the printed proxy address, use the proxy // and exit with Ctrl-C. It will throw error if your haven't acutally used the proxy if os.Args[len(os.Args)-1] != "server" { return } proxy := goproxy.NewProxyHttpServer() println("proxy localhost port 8082") access := int32(0) proxy.OnRequest().Do(auth.Basic("my_realm", func(user, passwd string) bool { atomic.AddInt32(&access, 1) return user == "user" && passwd == "1234" })) l, err := net.Listen("tcp", "localhost:8082") if err != nil { t.Fatal(err) } ch := make(chan os.Signal) signal.Notify(ch, os.Interrupt) go func() { <-ch l.Close() }() http.Serve(l, proxy) if access <= 0 { t.Error("No one accessed the proxy") } }
func TestBasicAuthWithCurl(t *testing.T) { expected := ":c>" background := httptest.NewServer(ConstantHandler(expected)) defer background.Close() proxy := goproxy.NewProxyHttpServer() proxy.OnRequest().Do(auth.Basic("my_realm", func(user, passwd string) bool { return user == "user" && passwd == "open sesame" })) _, proxyserver := oneShotProxy(proxy) defer proxyserver.Close() cmd := exec.Command("curl", "--silent", "--show-error", "-x", proxyserver.URL, "-U", "user:open sesame", "--url", background.URL+"/[1-3]", ) out, err := cmd.CombinedOutput() // if curl got error, it'll show up in stderr if err != nil { t.Fatal(err, string(out)) } finalexpected := times(3, expected) if string(out) != finalexpected { t.Error("Expected", finalexpected, "got", string(out)) } }
func TestGoproxyHijackConnect(t *testing.T) { proxy := goproxy.NewProxyHttpServer() hijackHandler := goproxy.HandlerFunc(func(ctx *goproxy.ProxyCtx) goproxy.Next { req := ctx.Req client := ctx.HijackConnect() t.Logf("URL %+#v\nSTR %s", req.URL, req.URL.String()) resp, err := http.Get("http:" + req.URL.String() + "/bobo") panicOnErr(err, "http.Get(CONNECT url)") panicOnErr(resp.Write(client), "resp.Write(client)") resp.Body.Close() client.Close() return goproxy.DONE }) proxy.HandleRequest(goproxy.RequestHostIsIn(srv.Listener.Addr().String())(hijackHandler)) client, l := oneShotProxy(proxy, t) defer l.Close() proxyAddr := l.Listener.Addr().String() conn, err := net.Dial("tcp", proxyAddr) panicOnErr(err, "conn "+proxyAddr) buf := bufio.NewReader(conn) writeConnect(conn) readConnectResponse(buf) if txt := readResponse(buf); txt != "bobo" { t.Error("Expected bobo for CONNECT /foo, got", txt) } if r := string(getOrFail(https.URL+"/bobo", client, t)); r != "bobo" { t.Error("Expected bobo would keep working with CONNECT", r) } }
func main() { verbose := flag.Bool("v", false, "should every proxy request be logged to stdout") addr := flag.String("addr", ":8080", "proxy listen address") flag.Parse() proxy := goproxy.NewProxyHttpServer() proxy.Verbose = *verbose log.Fatal(proxy.ListenAndServe(*addr)) }
func TestSelfRequest(t *testing.T) { proxy := goproxy.NewProxyHttpServer() _, l := oneShotProxy(proxy, t) defer l.Close() if !strings.Contains(string(getOrFail(l.URL, http.DefaultClient, t)), "non-proxy") { t.Fatal("non proxy requests should fail") } }
func TestHeadReqHasContentLength(t *testing.T) { client, l := oneShotProxy(goproxy.NewProxyHttpServer(), t) defer l.Close() resp, err := client.Head(localFile("test_data/panda.png")) panicOnErr(err, "resp to HEAD") if resp.Header.Get("Content-Length") == "" { t.Error("Content-Length should exist on HEAD requests") } }
func TestNoProxyHeaders(t *testing.T) { s := httptest.NewServer(VerifyNoProxyHeaders{t}) client, l := oneShotProxy(goproxy.NewProxyHttpServer(), t) defer l.Close() req, err := http.NewRequest("GET", s.URL, nil) panicOnErr(err, "bad request") req.Header.Add("Connection", "close") req.Header.Add("Proxy-Connection", "close") client.Do(req) }
func main() { proxy := goproxy.NewProxyHttpServer() daytimeBlocker := goproxy.HandlerFunc(func(ctx *goproxy.ProxyCtx) goproxy.Next { if h, _, _ := time.Now().Clock(); h >= 8 && h <= 17 { ctx.NewResponse(http.StatusForbidden, "text/plain", "Don't waste your time!") return goproxy.FORWARD } return goproxy.NEXT }) proxy.HandleRequest(goproxy.RequestHostIsIn("www.reddit.com")(daytimeBlocker)) log.Fatalln(proxy.ListenAndServe(":8080")) }
func main() { verbose := flag.Bool("v", false, "should every proxy request be logged to stdout") addr := flag.String("addr", ":8080", "proxy listen address") flag.Parse() proxy := goproxy.NewProxyHttpServer() proxy.Transport.Dial = func(network, addr string) (c net.Conn, err error) { c, err = net.Dial(network, addr) if c, ok := c.(*net.TCPConn); err != nil && ok { c.SetKeepAlive(true) } return } proxy.Verbose = *verbose log.Fatal(proxy.ListenAndServe(*addr)) }
func TestConnectHandler(t *testing.T) { proxy := goproxy.NewProxyHttpServer() althttps := httptest.NewTLSServer(ConstantHandler("althttps")) proxy.HandleConnectFunc(func(ctx *goproxy.ProxyCtx) goproxy.Next { u, _ := url.Parse(althttps.URL) ctx.SetDestinationHost(u.Host) return goproxy.FORWARD }) client, l := oneShotProxy(proxy, t) defer l.Close() if resp := string(getOrFail(https.URL+"/alturl", client, t)); resp != "althttps" { t.Error("Proxy should redirect CONNECT requests to local althttps server, expected 'althttps' got ", resp) } }
func TestAlwaysHook(t *testing.T) { proxy := goproxy.NewProxyHttpServer() proxy.HandleRequestFunc(func(ctx *goproxy.ProxyCtx) goproxy.Next { ctx.Req.URL.Path = "/bobo" return goproxy.NEXT }) client, l := oneShotProxy(proxy, t) defer l.Close() if result := string(getOrFail(srv.URL+("/momo"), client, t)); result != "bobo" { t.Error("Redirecting all requests from 127.0.0.1 to bobo, didn't work." + " (Might break if Go's client sets RemoteAddr to IPv6 address). Got: " + result) } }
func main() { verbose := flag.Bool("v", false, "should every proxy request be logged to stdout") addr := flag.String("addr", ":8080", "proxy listen address") flag.Parse() proxy := goproxy.NewProxyHttpServer() proxy.HandleConnect(goproxy.AlwaysMitm) proxy.HandleRequestFunc(func(ctx *goproxy.ProxyCtx) goproxy.Next { if ctx.Req.URL.Scheme == "https" { ctx.Req.URL.Scheme = "http" } return goproxy.NEXT }) proxy.Verbose = *verbose log.Fatal(proxy.ListenAndServe(*addr)) }
func TestSimpleMitmWithoutSNI(t *testing.T) { proxy := goproxy.NewProxyHttpServer() proxy.HandleConnectFunc(func(ctx *goproxy.ProxyCtx) goproxy.Next { return goproxy.MITM }) client, l := oneShotProxy(proxy, t) defer l.Close() if resp := string(getOrFail(https.URL+"/bobo", client, t)); resp != "bobo" { t.Error("Wrong response when mitm", resp, "expected bobo") } if resp := string(getOrFail(https.URL+"/query?result=bar", client, t)); resp != "bar" { t.Error("Wrong response when mitm", resp, "expected bar") } }
func TestHasGoproxyCA(t *testing.T) { proxy := goproxy.NewProxyHttpServer() proxy.HandleConnect(goproxy.AlwaysMitm) s := httptest.NewServer(proxy) proxyUrl, _ := url.Parse(s.URL) goproxyCA := x509.NewCertPool() goproxyCA.AddCert(goproxy.GoproxyCa.Leaf) tr := &http.Transport{TLSClientConfig: &tls.Config{RootCAs: goproxyCA}, Proxy: http.ProxyURL(proxyUrl)} client := &http.Client{Transport: tr} if resp := string(getOrFail(https.URL+"/bobo", client, t)); resp != "bobo" { t.Error("Wrong response when mitm", resp, "expected bobo") } }
func main() { proxy := goproxy.NewProxyHttpServer() proxy.OnResponse().Do(goproxy_image.HandleImage(func(img image.Image, ctx *goproxy.ProxyCtx) image.Image { dx, dy := img.Bounds().Dx(), img.Bounds().Dy() nimg := image.NewRGBA(img.Bounds()) for i := 0; i < dx; i++ { for j := 0; j <= dy; j++ { nimg.Set(i, j, img.At(i, dy-j-1)) } } return nimg })) proxy.Verbose = true log.Fatal(proxy.ListenAndServe(":8080")) }
func main() { verbose := flag.Bool("v", false, "should every proxy request be logged to stdout") addr := flag.String("l", ":8080", "on which address should the proxy listen") flag.Parse() proxy := goproxy.NewProxyHttpServer() proxy.Verbose = *verbose if err := os.MkdirAll("db", 0755); err != nil { log.Fatal("Can't create dir", err) } logger, err := NewLogger("db") if err != nil { log.Fatal("can't open log file", err) } tr := transport.Transport{Proxy: transport.ProxyFromEnvironment} proxy.OnRequest().DoFunc(func(req *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) { ctx.RoundTripper = goproxy.RoundTripperFunc(func(req *http.Request, ctx *goproxy.ProxyCtx) (resp *http.Response, err error) { details, resp, err = tr.DetailedRoundTrip(req) ctx.UserObjects["details"] = details return }) logger.LogReq(req, ctx) return req, nil }) proxy.OnResponse().DoFunc(func(resp *http.Response, ctx *goproxy.ProxyCtx) *http.Response { logger.LogResp(resp, ctx) return resp }) l, err := net.Listen("tcp", *addr) if err != nil { log.Fatal("listen:", err) } sl := newStoppableListener(l) ch := make(chan os.Signal) signal.Notify(ch, os.Interrupt) go func() { <-ch log.Println("Got SIGINT exiting") sl.Add(1) sl.Close() logger.Close() sl.Done() }() log.Println("Starting Proxy") http.Serve(sl, proxy) sl.Wait() log.Println("All connections closed - exit") }
func TestFirstHandlerMatches(t *testing.T) { proxy := goproxy.NewProxyHttpServer() proxy.HandleRequestFunc(func(ctx *goproxy.ProxyCtx) goproxy.Next { ctx.NewTextResponse("koko") return goproxy.FORWARD }) proxy.HandleRequestFunc(func(ctx *goproxy.ProxyCtx) goproxy.Next { panic("should never get here, because of the previous FORWARD") }) client, l := oneShotProxy(proxy, t) defer l.Close() if resp := string(getOrFail(srv.URL+"/", client, t)); resp != "koko" { t.Error("should return always koko and not", resp) } }
func TestBasicAuth(t *testing.T) { expected := "hello" background := httptest.NewServer(ConstantHandler(expected)) defer background.Close() proxy := goproxy.NewProxyHttpServer() proxy.OnRequest().Do(auth.Basic("my_realm", func(user, passwd string) bool { return user == "user" && passwd == "open sesame" })) client, proxyserver := oneShotProxy(proxy) defer proxyserver.Close() // without auth resp, err := client.Get(background.URL) if err != nil { t.Fatal(err) } if resp.Header.Get("Proxy-Authenticate") != "Basic realm=my_realm" { t.Error("Expected Proxy-Authenticate header got", resp.Header.Get("Proxy-Authenticate")) } if resp.StatusCode != 407 { t.Error("Expected status 407 Proxy Authentication Required, got", resp.Status) } // with auth req, err := http.NewRequest("GET", background.URL, nil) if err != nil { t.Fatal(err) } req.Header.Set("Proxy-Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte("user:open sesame"))) resp, err = client.Do(req) if err != nil { t.Fatal(err) } if resp.StatusCode != 200 { t.Error("Expected status 200 OK, got", resp.Status) } msg, err := ioutil.ReadAll(resp.Body) if err != nil { t.Fatal(err) } if string(msg) != "hello" { t.Errorf("Expected '%s', actual '%s'", expected, string(msg)) } }
func TestSimpleHttpReqWithProxy(t *testing.T) { proxy := goproxy.NewProxyHttpServer() proxy.Verbose = true client, s := oneShotProxy(proxy, t) defer s.Close() if r := string(getOrFail(srv.URL+"/bobo", client, t)); r != "bobo" { t.Error("proxy server does not serve constant handlers", r) } if r := string(getOrFail(srv.URL+"/bobo", client, t)); r != "bobo" { t.Error("proxy server does not serve constant handlers", r) } // NOTE: This issues a CONNECT call, because it doesn't default to port 80 ?? if string(getOrFail(https.URL+"/bobo", client, t)) != "bobo" { t.Error("TLS server does not serve constant handlers, when proxy is used") } }
func TestMitmIsFiltered(t *testing.T) { proxy := goproxy.NewProxyHttpServer() //proxy.Verbose = true proxy.HandleConnect(goproxy.AlwaysMitm) // PREVIOUSLY: proxy.OnRequest(goproxy.ReqHostIs(https.Listener.Addr().String())).HandleConnect(goproxy.AlwaysMitm) proxy.HandleRequest(goproxy.UrlIsIn("/momo")(goproxy.HandlerFunc(func(ctx *goproxy.ProxyCtx) goproxy.Next { ctx.NewTextResponse("koko") return goproxy.FORWARD }))) client, l := oneShotProxy(proxy, t) defer l.Close() if resp := string(getOrFail(https.URL+"/momo", client, t)); resp != "koko" { t.Error("Proxy should capture /momo to be koko and not", resp) } if resp := string(getOrFail(https.URL+"/bobo", client, t)); resp != "bobo" { t.Error("But still /bobo should be 'bobo' and not", resp) } }
func TestOneShotFileServer(t *testing.T) { client, l := oneShotProxy(goproxy.NewProxyHttpServer(), t) defer l.Close() file := "test_data/panda.png" info, err := os.Stat(file) if err != nil { t.Fatal("Cannot find", file) } if resp, err := client.Get(fs.URL + "/" + file); err == nil { b, err := ioutil.ReadAll(resp.Body) if err != nil { t.Fatal("got", string(b)) } if int64(len(b)) != info.Size() { t.Error("Expected Length", file, info.Size(), "actually", len(b), "starts", string(b[:10])) } } else { t.Fatal("Cannot read from fs server", err) } }
func TestChangeResp(t *testing.T) { proxy := goproxy.NewProxyHttpServer() proxy.HandleResponseFunc(func(ctx *goproxy.ProxyCtx) goproxy.Next { ctx.Resp.Body.Read([]byte{0}) ctx.Resp.Body = ioutil.NopCloser(new(bytes.Buffer)) return goproxy.NEXT }) client, l := oneShotProxy(proxy, t) defer l.Close() resp, err := client.Get(localFile("test_data/panda.png")) if err != nil { t.Fatal(err) } ioutil.ReadAll(resp.Body) _, err = client.Get(localFile("/bobo")) if err != nil { t.Fatal(err) } }
func NewJqueryVersionProxy() *goproxy.ProxyHttpServer { proxy := goproxy.NewProxyHttpServer() m := make(map[string]string) jqueryMatcher := regexp.MustCompile(`(?i:jquery\.)`) proxy.OnResponse(goproxy_html.IsHtml).Do(goproxy_html.HandleString( func(s string, ctx *goproxy.ProxyCtx) string { //ctx.Warnf("Charset %v by %v",ctx.Charset(),ctx.Req.Header["Content-Type"]) for _, src := range findScriptSrc(s) { if jqueryMatcher.MatchString(src) { prev, ok := m[ctx.Req.Host] if ok && prev != src { ctx.Warnf("In %v, Contradicting jqueries %v %v", ctx.Req.URL, prev, src) break } m[ctx.Req.Host] = src } } return s })) return proxy }
func TestCharset(t *testing.T) { s := httptest.NewServer(ConstantServer(1)) defer s.Close() ch := make(chan string, 2) proxy := goproxy.NewProxyHttpServer() proxy.OnResponse().Do(goproxy_html.HandleString( func(s string, ctx *goproxy.ProxyCtx) string { ch <- s return s })) proxyServer := httptest.NewServer(proxy) defer proxyServer.Close() proxyUrl, _ := url.Parse(proxyServer.URL) client := &http.Client{Transport: &http.Transport{Proxy: http.ProxyURL(proxyUrl)}} resp, err := client.Get(s.URL + "/cp1255.txt") if err != nil { t.Fatal("GET:", err) } b, err := ioutil.ReadAll(resp.Body) if err != nil { t.Fatal("readAll:", err) } resp.Body.Close() inHandleString := "" select { case inHandleString = <-ch: default: } if len(b) != 2 || b[0] != 0xe3 || b[1] != 0xf3 { t.Error("Did not translate back to 0xe3,0xf3, instead", b) } if inHandleString != "דף" { t.Error("HandleString did not convert DALET & PEH SOFIT (דף) from ISO-8859-8 to utf-8, got", []byte(inHandleString)) } }
func TestIcyResponse(t *testing.T) { // TODO: fix this test return // skip for now s := constantHttpServer([]byte("ICY 200 OK\r\n\r\nblablabla")) proxy := goproxy.NewProxyHttpServer() proxy.Verbose = true _, l := oneShotProxy(proxy, t) defer l.Close() req, err := http.NewRequest("GET", "http://"+s, nil) panicOnErr(err, "newReq") proxyip := l.URL[len("http://"):] println("got ip: " + proxyip) c, err := net.Dial("tcp", proxyip) panicOnErr(err, "dial") defer c.Close() req.WriteProxy(c) raw, err := ioutil.ReadAll(c) panicOnErr(err, "readAll") if string(raw) != "ICY 200 OK\r\n\r\nblablabla" { t.Error("Proxy did not send the malformed response received") } }