func TestFirstHandlerMatches(t *testing.T) { client, proxy, l := oneShotProxy(t) defer l.Close() proxy.OnRequest().DoFunc(func(req *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) { return nil, goproxy.TextResponse(req, "koko") }) proxy.OnRequest().DoFunc(func(req *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) { panic("should never get here, previous response is no null") return nil, nil }) if resp := string(getOrFail(srv.URL+"/", client, t)); resp != "koko" { t.Error("should return always koko and not", resp) } }
func TestMitmIsFiltered(t *testing.T) { client, proxy, l := oneShotProxy(t) defer l.Close() //proxy.Verbose = true proxy.OnRequest(goproxy.ReqHostIs(https.Listener.Addr().String())).HandleConnect(goproxy.AlwaysMitm) proxy.OnRequest(goproxy.UrlIs("/momo")).DoFunc(func(req *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) { return nil, goproxy.TextResponse(req, "koko") }) 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 main() { verbose := flag.Bool("v", false, "should every proxy request be logged to stdout") addr := flag.String("addr", ":8080", "proxy listen address") java := flag.String("javapath", "java", "where the Java executable is located") yuicompressor := flag.String("yuicompressor", "", "where the yuicompressor is located, assumed to be in CWD") yuicompressordir := flag.String("yuicompressordir", ".", "a folder to search yuicompressor in, will be ignored if yuicompressor is set") flag.Parse() if *yuicompressor == "" { files, err := ioutil.ReadDir(*yuicompressordir) if err != nil { log.Fatal("Cannot find yuicompressor jar") } for _, file := range files { if strings.HasPrefix(file.Name(), "yuicompressor") && strings.HasSuffix(file.Name(), ".jar") { c := path.Join(*yuicompressordir, file.Name()) yuicompressor = &c break } } } if *yuicompressor == "" { log.Fatal("Can't find yuicompressor jar, searched yuicompressor*.jar in dir ", *yuicompressordir) } if _, err := os.Stat(*yuicompressor); os.IsNotExist(err) { log.Fatal("Can't find yuicompressor jar specified ", *yuicompressor) } proxy := goproxy.NewProxyHttpServer() proxy.Verbose = *verbose proxy.OnResponse().DoFunc(func(resp *http.Response, ctx *goproxy.ProxyCtx) *http.Response { contentType := resp.Header.Get("Content-Type") if contentType == "application/javascript" || contentType == "application/x-javascript" { // in real code, response should be streamed as well var err error cmd := exec.Command(*java, "-jar", *yuicompressor, "--type", "js") cmd.Stdin = resp.Body resp.Body, err = cmd.StdoutPipe() if err != nil { ctx.Warnf("Cannot minify content in %v: %v", ctx.Req.URL, err) return goproxy.TextResponse(ctx.Req, "Error getting stdout pipe") } stderr, err := cmd.StderrPipe() if err != nil { ctx.Logf("Error obtaining stderr from yuicompress: %s", err) return goproxy.TextResponse(ctx.Req, "Error getting stderr pipe") } if err := cmd.Start(); err != nil { ctx.Warnf("Cannot minify content in %v: %v", ctx.Req.URL, err) } go func() { defer stderr.Close() const kb = 1024 msg, err := ioutil.ReadAll(&io.LimitedReader{stderr, 50 * kb}) if len(msg) != 0 { ctx.Logf("Error executing yuicompress: %s", string(msg)) } if err != nil { ctx.Logf("Error reading stderr from yuicompress: %s", string(msg)) } }() } return resp }) log.Fatal(http.ListenAndServe(*addr, proxy)) }
func TestHttpsMitmURLRewrite(t *testing.T) { scheme := "https" testCases := []struct { Host string RawPath string AddOpaque bool }{ { Host: "example.com", RawPath: "/blah/v1/data/realtime", AddOpaque: true, }, { Host: "example.com:443", RawPath: "/blah/v1/data/realtime?encodedURL=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile", }, { Host: "example.com:443", RawPath: "/blah/v1/data/realtime?unencodedURL=https://www.googleapis.com/auth/userinfo.profile", }, } for _, tc := range testCases { proxy := goproxy.NewProxyHttpServer() proxy.OnRequest().HandleConnect(goproxy.AlwaysMitm) proxy.OnRequest(goproxy.DstHostIs(tc.Host)).DoFunc( func(req *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) { return nil, goproxy.TextResponse(req, "Dummy response") }) client, s := oneShotProxy(proxy, t) defer s.Close() fullURL := scheme + "://" + tc.Host + tc.RawPath req, err := http.NewRequest("GET", fullURL, nil) if err != nil { t.Fatal(err) } if tc.AddOpaque { req.URL.Scheme = scheme req.URL.Opaque = "//" + tc.Host + tc.RawPath } resp, err := client.Do(req) if err != nil { t.Fatal(err) } b, err := ioutil.ReadAll(resp.Body) defer resp.Body.Close() if err != nil { t.Fatal(err) } body := string(b) if body != "Dummy response" { t.Errorf("Expected proxy to return dummy body content but got %s", body) } if resp.StatusCode != http.StatusAccepted { t.Errorf("Expected status: %d, got: %d", http.StatusAccepted, resp.StatusCode) } } }