Example #1
0
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}
	// For every incoming request, override the RoundTripper to extract
	// connection information. Store it is session context log it after
	// handling the response.
	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) {
			ctx.UserData, resp, err = tr.DetailedRoundTrip(req)
			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")
}
Example #2
0
func main() {
	cwd, _ := os.Getwd()

	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")
	cacheDir := flag.String("p", cwd, "cache directory, by default the working directory")
	flag.Parse()

	proxy := goproxy.NewProxyHttpServer()
	proxy.Verbose = *verbose

	store, err := NewPkgStore(*cacheDir)
	if err != nil {
		log.Fatal(fmt.Printf("Could not create package cache directory: %s", *cacheDir))
	} else {
		log.Printf("Using cache directory: %s", *cacheDir)
	}

	tr := transport.Transport{Proxy: transport.ProxyFromEnvironment}
	r := regexp.MustCompile(`/([^/]+)/os/(i686|x86_64)/(.+\.pkg\.tar.+)`)

	proxy.OnRequest().DoFunc(func(req *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) {
		uri := req.URL.RequestURI()
		if r.MatchString(uri) == true {
			pkgInfo := r.FindStringSubmatch(uri)
			pkgFile := store.NewPkg(pkgInfo[1], pkgInfo[2], pkgInfo[3])
			log.Printf("Request: %s/%s/%s", pkgFile.repo, pkgFile.arch, pkgFile.fname)

			if store.HasPkg(pkgFile) {
				log.Printf("Serving cached package: %s/%s/%s", pkgFile.repo, pkgFile.arch, pkgFile.fname)
				return req, NewCachedResponse(req, store, pkgFile)
			} else {
				ctx.RoundTripper = goproxy.RoundTripperFunc(func(req *http.Request, ctx *goproxy.ProxyCtx) (resp *http.Response, err error) {
					resp, err = tr.RoundTrip(req)
					ctx.UserData = pkgFile
					return
				})
			}
		}
		return req, nil
	})
	proxy.OnResponse().DoFunc(func(resp *http.Response, ctx *goproxy.ProxyCtx) *http.Response {
		if ctx.UserData != nil {
			store.PutPkg(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()
		sl.Done()
	}()

	log.Println("Starting Proxy")
	http.Serve(sl, proxy)
	sl.Wait()
	log.Println("All connections closed - exit")
}
Example #3
0
func NewProxy(cfg Config) (*goproxy.ProxyHttpServer, error) {
	proxy := goproxy.NewProxyHttpServer()

	// Use two transports, one secure (certificate checks are
	// done) and one insecure.
	secureTransport := &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: false}}
	insecureTransport := &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}

	log.Info("start serving requests on %s", cfg.Proxy.Listen)

	// Register configuration inside context
	proxy.OnRequest().
		DoFunc(func(req *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) {
			url := fmt.Sprintf("%s://%s%s",
				req.URL.Scheme, req.URL.Host, req.URL.Path)
			ctx.UserData = cfg.UrlConfiguration(url)
			return req, nil
		})

	// Remove X-Frame-Options header
	proxy.OnResponse().
		DoFunc(func(resp *http.Response, ctx *goproxy.ProxyCtx) *http.Response {
			if resp != nil {
				allowed := ctx.UserData.(*UrlConfig).Allow_Framing
				if allowed != nil && *allowed {
					resp.Header.Del("X-Frame-Options")
				}
			}
			return resp
		})

	// Add X-Forwarded-For header
	proxy.OnRequest().
		DoFunc(func(req *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) {
			x := ctx.UserData.(*UrlConfig).Append_XForwardedFor
			if x != nil && *x {
				src := strings.Split(ctx.Req.RemoteAddr, ":")[0]
				req.Header.Set("X-Forwarded-For", src)
			}
			return req, nil
		})

	// Make the request over HTTPS
	proxy.OnRequest().
		DoFunc(func(req *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) {
			ssl := ctx.UserData.(*UrlConfig).Https
			if ssl != nil && *ssl {
				// For tests, we also need to get the
				// appropriate port for SSL. We expect to
				// found it in X-Test-HTTPS header.
				host := req.Header.Get("X-Test-HTTPS")
				if host != "" {
					req.URL.Host = host[8:]
				}
				req.URL.Scheme = "https"
			}
			return req, nil
		})

	// Convert back location to non-HTTP
	proxy.OnResponse().
		DoFunc(func(resp *http.Response, ctx *goproxy.ProxyCtx) *http.Response {
			if resp == nil {
				return resp
			}
			location := resp.Header.Get("Location")
			if location == "" {
				return resp
			}
			// If the requested location would have been
			// redirected to HTTPS, give it back as an HTTP
			// location.
			url, err := url.Parse(location)
			if err != nil || url.Scheme != "https" {
				return resp
			}
			// For testing purposes, the address of the right server is in X-Test-HTTP header
			host := resp.Header.Get("X-Test-HTTP")
			if host != "" {
				host = host[7:]
			}
			ncfg := cfg.UrlConfiguration(
				fmt.Sprintf("http://%s%s",
					host, url.Path))
			if ncfg.Https != nil && *ncfg.Https {
				url.Scheme = "http"
				url.Host = host
				resp.Header.Set("Location", url.String())
			}

			return resp
		})

	// For HTTPS, do certificate checks
	proxy.OnRequest().
		DoFunc(func(req *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) {
			if req.URL.Scheme != "https" {
				return req, nil
			}
			verify := ctx.UserData.(*UrlConfig).Https_Verify_Cert
			ctx.RoundTripper = goproxy.RoundTripperFunc(func(req *http.Request, ctx *goproxy.ProxyCtx) (*http.Response, error) {
				if verify != nil && *verify {
					log.Debug("proxy: selecting secure transport for %v", req.URL)
					return secureTransport.RoundTrip(req)
				} else {
					log.Debug("proxy: selecting insecure transport for %v", req.URL)
					return insecureTransport.RoundTrip(req)
				}
			})

			return req, nil
		})

	// Log requests
	if cfg.Proxy.Debug {
		proxy.OnResponse().
			DoFunc(func(resp *http.Response, ctx *goproxy.ProxyCtx) *http.Response {
				var status int
				if resp != nil {
					status = resp.StatusCode
				} else {
					status = 0
				}
				log.Debug("proxy: from %s: %d: %s %s %s",
					ctx.Req.RemoteAddr,
					status,
					ctx.Req.Method,
					ctx.Req.URL.String(),
					ctx.Req.Proto)
				return resp
			})
	}

	return proxy, nil
}