<commit_before>package main

import (
	"flag"
	"bufio"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"log"
	"net/http"
	"strconv"
	"strings"
	"regexp"
)

var (
	warpAddr      = flag.String("warp.addr", "127.0.0.1:4242", "Address of sensision")
	listenAddress = flag.String("web.listen-address", ":9121", "Address to listen on for web interface and telemetry.")
	metricPath    = flag.String("web.telemetry-path", "/metrics", "Path under which to expose metrics.")
	debug         = flag.Bool("debug", false, "Debug mode displays what is fetch.")
)

var reg   *regexp.Regexp

func init() {
	reg = regexp.MustCompile(`((?:\.?\w+)+)\{([^}]*)\} (\w*)`)
}

type warp struct {
	warpAddr string
	metrics  map[string]warpMetric
}

type warpMetric struct {
	desc    *prometheus.Desc
	valType prometheus.ValueType
}

func parseFloatOrZero(s string) float64 {
	res, err := strconv.ParseFloat(s, 64)
	if err != nil {
		log.Printf("Cannot parse %s\n", s)
		return 0.0
	}
	return res
}

func newWarpExporter(addr string) *warp {
	e := warp{
		warpAddr: addr,
		metrics: map[string]warpMetric{
			"warp_ingress_update_requests": {
				desc:    prometheus.NewDesc("warp_ingress_update_requests", "Number of request", nil, nil),
				valType: prometheus.CounterValue,
			},
			"warp_ingress_update_parseerrors": {
				desc:    prometheus.NewDesc("warp_ingress_update_parseerrors", "Number of parse error", nil, nil),
				valType: prometheus.CounterValue,
			},
			"warp_ingress_update_invalidtoken": {
				desc:    prometheus.NewDesc("warp_ingress_update_invalidtoken", "Number of invalid token", nil, nil),
				valType: prometheus.CounterValue,
			},
			"warp_directory_streaming_requests": {
				desc:    prometheus.NewDesc("warp_directory_streaming_requests", "Number of directory request", nil, nil),
				valType: prometheus.CounterValue,
			},
			"warp_directory_metadata_cache_hits": {
				desc:    prometheus.NewDesc("warp_directory_metadata_cache_hits", "Number of directory cache hit", nil, nil),
				valType: prometheus.GaugeValue,
			},
			"warp_directory_hbase_puts": {
				desc:    prometheus.NewDesc("warp_directory_hbase_puts", "Number of directory hbase puts", nil, nil),
				valType: prometheus.GaugeValue,
			},
			"warp_directory_kafka_faileddecrypts": {
				desc:    prometheus.NewDesc("warp_directory_kafka_faileddecrypts", "Fail to descrypt kafka message", nil, nil),
				valType: prometheus.CounterValue,
			},
			"warp_directory_gts": {
				desc:    prometheus.NewDesc("warp_directory_gts", "Number of GTS metadata managed by Directory", nil, nil),
				valType: prometheus.GaugeValue,
			},
			"warp_store_hbase_puts_committed": {
				desc: prometheus.NewDesc("warp_store_hbase_puts_committed", "Number of HBase Puts committed in Store", nil, nil),
				valType: prometheus.GaugeValue,
			},
			"warp_script_requests" : {
				desc: prometheus.NewDesc("warp_script_requests", "Number of script request", nil, nil),
				valType: prometheus.GaugeValue,
			},
			"warp_script_ops" : {
				desc: prometheus.NewDesc("warp_script_ops", "Number of ops executed", nil, nil),
				valType: prometheus.GaugeValue,
			},
			"warp_hbase_client_scanners" : {
				desc: prometheus.NewDesc("warp_hbase_client_scanners", "Number of hbase client scanners", nil, nil),
				valType: prometheus.GaugeValue,
			},
			"warp_store_aborts"  :{
				desc: prometheus.NewDesc("warp_store_aborts", "Number of aborts experienced", nil, nil),
				valType: prometheus.GaugeValue,
			},
			"warp_store_hbase_conn_resets" : {
				desc: prometheus.NewDesc("warp_store_hbase_conn_resets", "Number of times the HBase connection was reset", nil, nil),
				valType: prometheus.GaugeValue,
			},
			"warp_store_kafka_commits_overdue" : {
				desc: prometheus.NewDesc("warp_store_kafka_commits_overdue", "Number of kafka commits overdue", nil, nil),
				valType: prometheus.GaugeValue,
			},
			"warp_store_gtsdecoders" : {
				desc: prometheus.NewDesc("warp_store_gtsdecoders", "Number of gts decoded", nil, nil),
				valType: prometheus.GaugeValue,
			},
			"warp_throttling_rate_global" : {
				desc: prometheus.NewDesc("warp_throttling_rate_global", "Throtlling rate", nil, nil),
				valType: prometheus.CounterValue,
			},
		},
	}
	return &e
}

func (w *warp) scrapeSensisionMetrics(ch chan<- prometheus.Metric) {
	resp, err := http.Get("http://" + w.warpAddr + "/metrics")
	if err == nil {
		defer resp.Body.Close()
		scanner := bufio.NewScanner(resp.Body)
		for scanner.Scan() {
			line := scanner.Text()
			tokens := reg.FindAllStringSubmatch(strings.Trim(line, "\t\r\n"), -1)
			metric_name := strings.Replace(tokens[0][1], ".", "_", -1)
			if val, ok := w.metrics[metric_name]; ok {
				value := parseFloatOrZero(tokens[0][3])
				if *debug {
					log.Printf("Sensision output %s\n", line)
					log.Printf("Metric name %s, value %f\n", metric_name, value)
				}
				ch <- prometheus.MustNewConstMetric(val.desc, val.valType, value)
			}
		}
	} else {
		log.Printf("Cannot fetch sensision output\n")
	}
}

func (w *warp) Describe(ch chan<- *prometheus.Desc) {
	for _, i := range w.metrics {
		ch <- i.desc
	}
}

func (w *warp) Collect(ch chan<- prometheus.Metric) {
	if *debug {
		log.Printf("Start collecting")
	}
	w.scrapeSensisionMetrics(ch)
	if *debug {
		log.Printf("Stop collecting")
	}
}

func main() {
	flag.Parse()
	e := newWarpExporter(*warpAddr)
	prometheus.MustRegister(e)
	http.Handle(*metricPath, promhttp.Handler())
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte(`
		       <title>Warp10 exporter</title>

Warp10 exporter

<a href='` + *metricPath + `'>Metrics

		       `))
	})
	log.Printf("providing metrics at %s%s", *listenAddress, *metricPath)
	log.Fatal(http.ListenAndServe(*listenAddress, nil))
}
<commit_msg>Add metrics<commit_after>package main

import (
	"flag"
	"bufio"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"log"
	"net/http"
	"strconv"
	"strings"
	"regexp"
)

var (
	warpAddr      = flag.String("warp.addr", "127.0.0.1:4242", "Address of sensision")
	listenAddress = flag.String("web.listen-address", ":9121", "Address to listen on for web interface and telemetry.")
	metricPath    = flag.String("web.telemetry-path", "/metrics", "Path under which to expose metrics.")
	debug         = flag.Bool("debug", false, "Debug mode displays what is fetch.")
)

var reg   *regexp.Regexp

func init() {
	reg = regexp.MustCompile(`((?:\.?\w+)+)\{([^}]*)\} (\w*)`)
}

type warp struct {
	warpAddr string
	metrics  map[string]warpMetric
}

type warpMetric struct {
	desc    *prometheus.Desc
	valType prometheus.ValueType
}

func parseFloatOrZero(s string) float64 {
	res, err := strconv.ParseFloat(s, 64)
	if err != nil {
		log.Printf("Cannot parse %s\n", s)
		return 0.0
	}
	return res
}

func newWarpExporter(addr string) *warp {
	e := warp{
		warpAddr: addr,
		metrics: map[string]warpMetric{
			"warp_ingress_update_requests": {
				desc:    prometheus.NewDesc("warp_ingress_update_requests", "Number of request", nil, nil),
				valType: prometheus.CounterValue,
			},
			"warp_ingress_update_parseerrors": {
				desc:    prometheus.NewDesc("warp_ingress_update_parseerrors", "Number of parse error", nil, nil),
				valType: prometheus.CounterValue,
			},
			"warp_ingress_update_invalidtoken": {
				desc:    prometheus.NewDesc("warp_ingress_update_invalidtoken", "Number of invalid token", nil, nil),
				valType: prometheus.CounterValue,
			},
			"warp_directory_streaming_requests": {
				desc:    prometheus.NewDesc("warp_directory_streaming_requests", "Number of directory request", nil, nil),
				valType: prometheus.CounterValue,
			},
			"warp_directory_metadata_cache_hits": {
				desc:    prometheus.NewDesc("warp_directory_metadata_cache_hits", "Number of directory cache hit", nil, nil),
				valType: prometheus.GaugeValue,
			},
			"warp_directory_hbase_puts": {
				desc:    prometheus.NewDesc("warp_directory_hbase_puts", "Number of directory hbase puts", nil, nil),
				valType: prometheus.GaugeValue,
			},
			"warp_directory_kafka_faileddecrypts": {
				desc:    prometheus.NewDesc("warp_directory_kafka_faileddecrypts", "Fail to descrypt kafka message", nil, nil),
				valType: prometheus.CounterValue,
			},
			"warp_directory_gts": {
				desc:    prometheus.NewDesc("warp_directory_gts", "Number of GTS metadata managed by Directory", nil, nil),
				valType: prometheus.GaugeValue,
			},
			"warp_store_hbase_puts_committed": {
				desc: prometheus.NewDesc("warp_store_hbase_puts_committed", "Number of HBase Puts committed in Store", nil, nil),
				valType: prometheus.GaugeValue,
			},
			"warp_script_requests" : {
				desc: prometheus.NewDesc("warp_script_requests", "Number of script request", nil, nil),
				valType: prometheus.GaugeValue,
			},
			"warp_script_ops" : {
				desc: prometheus.NewDesc("warp_script_ops", "Number of ops executed", nil, nil),
				valType: prometheus.GaugeValue,
			},
			"warp_hbase_client_scanners" : {
				desc: prometheus.NewDesc("warp_hbase_client_scanners", "Number of hbase client scanners", nil, nil),
				valType: prometheus.GaugeValue,
			},
			"warp_store_aborts"  :{
				desc: prometheus.NewDesc("warp_store_aborts", "Number of aborts experienced", nil, nil),
				valType: prometheus.GaugeValue,
			},
			"warp_store_hbase_conn_resets" : {
				desc: prometheus.NewDesc("warp_store_hbase_conn_resets", "Number of times the HBase connection was reset", nil, nil),
				valType: prometheus.GaugeValue,
			},
			"warp_store_kafka_commits_overdue" : {
				desc: prometheus.NewDesc("warp_store_kafka_commits_overdue", "Number of kafka commits overdue", nil, nil),
				valType: prometheus.GaugeValue,
			},
			"warp_store_gtsdecoders" : {
				desc: prometheus.NewDesc("warp_store_gtsdecoders", "Number of gts decoded", nil, nil),
				valType: prometheus.GaugeValue,
			},
			"warp_throttling_rate_perapp_global" : {
				desc: prometheus.NewDesc("warp_throttling_rate_perapp_global", "Throtlling rate", nil, nil),
				valType: prometheus.CounterValue,
			},
			"warp_ingress_update_datapoints_global" : {
				desc: prometheus.NewDesc("warp_ingress_update_datapoints_global", "Datapoints update per second", nil,nil),
				valType: prometheus.CounterValue,
			},
		},
	}
	return &e
}

func (w *warp) scrapeSensisionMetrics(ch chan<- prometheus.Metric) {
	resp, err := http.Get("http://" + w.warpAddr + "/metrics")
	if err == nil {
		defer resp.Body.Close()
		scanner := bufio.NewScanner(resp.Body)
		for scanner.Scan() {
			line := scanner.Text()
			tokens := reg.FindAllStringSubmatch(strings.Trim(line, "\t\r\n"), -1)
			metric_name := strings.Replace(tokens[0][1], ".", "_", -1)
			if val, ok := w.metrics[metric_name]; ok {
				value := parseFloatOrZero(tokens[0][3])
				if *debug {
					log.Printf("Sensision output %s\n", line)
					log.Printf("Metric name %s, value %f\n", metric_name, value)
				}
				ch <- prometheus.MustNewConstMetric(val.desc, val.valType, value)
			}
		}
	} else {
		log.Printf("Cannot fetch sensision output\n")
	}
}

func (w *warp) Describe(ch chan<- *prometheus.Desc) {
	for _, i := range w.metrics {
		ch <- i.desc
	}
}

func (w *warp) Collect(ch chan<- prometheus.Metric) {
	if *debug {
		log.Printf("Start collecting")
	}
	w.scrapeSensisionMetrics(ch)
	if *debug {
		log.Printf("Stop collecting")
	}
}

func main() {
	flag.Parse()
	e := newWarpExporter(*warpAddr)
	prometheus.MustRegister(e)
	http.Handle(*metricPath, promhttp.Handler())
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte(`
		       <title>Warp10 exporter</title>

Warp10 exporter

<a href='` + *metricPath + `'>Metrics

		       `))
	})
	log.Printf("providing metrics at %s%s", *listenAddress, *metricPath)
	log.Fatal(http.ListenAndServe(*listenAddress, nil))
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"regexp"
	"strconv"
	"strings"
	"text/template"
)

var httpFlag = flag.String("http", ":8080", "Serve HTTP at given address")
var httpsFlag = flag.String("https", "", "Serve HTTPS at given address")
var certFlag = flag.String("cert", "", "Use the provided TLS certificate")
var keyFlag = flag.String("key", "", "Use the provided TLS key")

func main() {
	if err := run(); err != nil {
		fmt.Fprintf(os.Stderr, "error: %v\n", err)
		os.Exit(1)
	}
}

func run() error {
	flag.Parse()
	if len(flag.Args()) > 0 {
		return fmt.Errorf("too many arguments: %s", flag.Args()[0])
	}

	http.HandleFunc("/", handler)

	if *httpFlag == "" && *httpsFlag == "" {
		return fmt.Errorf("must provide -http and/or -https")
	}
	if (*httpsFlag != "" || *certFlag != "" || *keyFlag != "") && (*httpsFlag == "" || *certFlag == "" || *keyFlag == "") {
		return fmt.Errorf("-https -cert and -key must be used together")
	}

	ch := make(chan error, 2)

	if *httpFlag != "" {
		go func() {
			ch <- http.ListenAndServe(*httpFlag, nil)
		}()
	}
	if *httpsFlag != "" {
		go func() {
			ch <- http.ListenAndServeTLS(*httpsFlag, *certFlag, *keyFlag, nil)
		}()
	}
	return <-ch
}

var tmplProxy = template.Must(template.New("").Parse(`
<html>
<head>
<meta name="go-import" content="{{.PkgRoot}} git {{.GitRoot}}">
</head>
<body>
<script>
window.location = "http://godoc.org/{{.PkgPath}}" + window.location.hash;
</script>
</body>
</html>
`))

type Repo struct {
	User       string // username or organization, might include forward slash
	Pkg        string // repository name
	VersionStr string // version string ("v1")
	Path       string // path inside repository
	Compat     bool   // when true, use old format

	Version  Version     // requested version (major only)
	Versions VersionList // available versions
}

func (repo *Repo) GitRoot() string {
	return "https://" + repo.PkgRoot()
}

func (repo *Repo) HubRoot() string {
	if len(repo.User) == 0 {
		return "https://github.com/go-" + repo.Pkg + "/" + repo.Pkg
	}
	return "https://github.com/" + repo.User + repo.Pkg
}

func (repo *Repo) PkgBase() string {
	return "gopkg.in/" + repo.User + repo.Pkg
}

func (repo *Repo) PkgRoot() string {
	if repo.Compat {
		return "gopkg.in/" + repo.User + repo.VersionStr + "/" + repo.Pkg
	}
	return repo.PkgBase() + "." + repo.VersionStr
}

func (repo *Repo) PkgPath() string {
	return repo.PkgRoot() + repo.Path
}

var patternOld = regexp.MustCompile(`^/([a-z0-9][-a-z0-9]+/)?((?:v0|v[1-9][0-9]*)(?:\.0|\.[1-9][0-9]*){0,2})/([a-zA-Z][-a-zA-Z0-9]*)(?:\.git)?((?:/[a-zA-Z][-a-zA-Z0-9]*)*)$`)
var patternNew = regexp.MustCompile(`^/([a-z0-9][-a-z0-9]+/)?([a-zA-Z][-a-zA-Z0-9]*)\.((?:v0|v[1-9][0-9]*)(?:\.0|\.[1-9][0-9]*){0,2})(?:\.git)?((?:/[a-zA-Z][-a-zA-Z0-9]*)*)$`)

func handler(resp http.ResponseWriter, req *http.Request) {
	if req.URL.Path == "/health-check" {
		resp.Write([]byte("ok"))
		return
	}

	log.Printf("%s requested %s", req.RemoteAddr, req.URL)

	if req.URL.Path == "/" {
		resp.Header().Set("Location", "http://labix.org/gopkg.in")
		resp.WriteHeader(http.StatusTemporaryRedirect)
		return
	}

	goget := req.FormValue("go-get") == "1"

	m := patternNew.FindStringSubmatch(req.URL.Path)
	compat := false
	if m == nil {
		m = patternOld.FindStringSubmatch(req.URL.Path)
		if m == nil {
			sendNotFound(resp, "Unsupported URL pattern; see the documentation at gopkg.in for details.")
			return
		}
		m[2], m[3] = m[3], m[2]
		compat = true
	}

	if strings.Contains(m[3], ".") {
		sendNotFound(resp, "Import paths take the major version only (.%s instead of .%s); see docs at gopkg.in for the reasoning.",
			m[3][:strings.Index(m[3], ".")], m[3])
		return
	}

	repo := &Repo{
		User:       m[1],
		Pkg:        m[2],
		VersionStr: m[3],
		Path:       m[4],
		Compat:     compat,
	}

	var ok bool
	repo.Version, ok = parseVersion(repo.VersionStr)
	if !ok {
		sendNotFound(resp, "Version %q improperly considered invalid; please warn the service maintainers.", m[3])
		return
	}

	// // Run this concurrently to avoid waiting later.
	// nameVersioned := nameHasVersion(repo)

	var err error
	var refs []byte
	refs, repo.Versions, err = hackedRefs(repo)
	switch err {
	case nil:
		// repo.GitRoot = "https://" + repo.PkgRoot
		// all ok
	case ErrNoRepo:
		// if <-nameVersioned {
		// 	v := repo.Version.String()
		// 	repo.GitRoot += "-" + v
		// 	repo.HubRoot += "-" + v
		// 	break
		// }
		sendNotFound(resp, "GitHub repository not found at %s", repo.HubRoot())
		return
	case ErrNoVersion:
		v := repo.Version.String()
		if repo.Version.Minor == -1 {
			sendNotFound(resp, `GitHub repository at %s has no branch or tag "%s", "%s.N" or "%s.N.M"`, repo.HubRoot(), v, v, v)
		} else if repo.Version.Patch == -1 {
			sendNotFound(resp, `GitHub repository at %s has no branch or tag "%s" or "%s.N"`, repo.HubRoot(), v, v)
		} else {
			sendNotFound(resp, `GitHub repository at %s has no branch or tag "%s"`, repo.HubRoot(), v)
		}
		return
	default:
		resp.WriteHeader(http.StatusBadGateway)
		resp.Write([]byte(fmt.Sprintf("Cannot obtain refs from GitHub: %v", err)))
		return
	}

	if m[4] == "/git-upload-pack" {
		resp.Header().Set("Location", repo.HubRoot()+"/git-upload-pack")
		resp.WriteHeader(http.StatusMovedPermanently)
		return
	}

	if m[4] == "/info/refs" {
		resp.Header().Set("Content-Type", "application/x-git-upload-pack-advertisement")
		resp.Write(refs)
		return
	}

	resp.Header().Set("Content-Type", "text/html")
	if goget {
		// execute simple template when this is a go-get request
		err = tmplProxy.Execute(resp, repo)
		if err != nil {
			log.Printf("error executing tmplProxy: %s\n", err)
		}
		return
	}

	renderInterface(resp, req, repo)
}

func sendNotFound(resp http.ResponseWriter, msg string, args ...interface{}) {
	if len(args) > 0 {
		msg = fmt.Sprintf(msg, args...)
	}
	resp.WriteHeader(http.StatusNotFound)
	resp.Write([]byte(msg))
}

// TODO Timeouts for these http interactions. Use the new support coming in 1.3.

const refsSuffix = ".git/info/refs?service=git-upload-pack"

// // Obsolete. Drop this.
// func nameHasVersion(repo *Repo) chan bool {
// 	ch := make(chan bool, 1)
// 	go func() {
// 		resp, err := http.Head(repo.HubRoot + "-" + repo.Version.String() + refsSuffix)
// 		if err != nil {
// 			ch <- false
// 			return
// 		}
// 		if resp.Body != nil {
// 			resp.Body.Close()
// 		}
// 		ch <- resp.StatusCode == 200
// 	}()
// 	return ch
// }

var ErrNoRepo = errors.New("repository not found in github")
var ErrNoVersion = errors.New("version reference not found in github")

func hackedRefs(repo *Repo) (data []byte, versions []Version, err error) {
	resp, err := http.Get(repo.HubRoot() + refsSuffix)
	if err != nil {
		return nil, nil, fmt.Errorf("cannot talk to GitHub: %v", err)
	}
	switch resp.StatusCode {
	case 200:
		defer resp.Body.Close()
	case 401, 404:
		return nil, nil, ErrNoRepo
	default:
		return nil, nil, fmt.Errorf("error from GitHub: %v", resp.Status)
	}

	data, err = ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, nil, fmt.Errorf("error reading from GitHub: %v", err)
	}

	var mrefi, mrefj int
	var vrefi, vrefj int
	var vrefv = InvalidVersion
	var unversioned = true

	versions = make([]Version, 0)
	sdata := string(data)
	for i, j := 0, 0; i < len(data); i = j {
		size, err := strconv.ParseInt(sdata[i:i+4], 16, 32)
		if err != nil {
			return nil, nil, fmt.Errorf("cannot parse refs line size: %s", string(data[i:i+4]))
		}
		if size == 0 {
			size = 4
		}
		j = i + int(size)
		if j > len(sdata) {
			return nil, nil, fmt.Errorf("incomplete refs data received from GitHub")
		}
		if sdata[0] == '#' {
			continue
		}

		hashi := i + 4
		hashj := strings.IndexByte(sdata[hashi:j], ' ')
		if hashj < 0 || hashj != 40 {
			continue
		}
		hashj += hashi

		namei := hashj + 1
		namej := strings.IndexAny(sdata[namei:j], "\n\x00")
		if namej < 0 {
			namej = j
		} else {
			namej += namei
		}

		name := sdata[namei:namej]

		if name == "refs/heads/master" {
			mrefi = hashi
			mrefj = hashj
		}

		if strings.HasPrefix(name, "refs/heads/v") || strings.HasPrefix(name, "refs/tags/v") {
			v, ok := parseVersion(name[strings.IndexByte(name, 'v'):])
			if ok && repo.Version.Contains(v) && (!vrefv.IsValid() || vrefv.Less(v)) {
				vrefv = v
				vrefi = hashi
				vrefj = hashj
			}
			if ok {
				unversioned = false
				versions = append(versions, v)
			}
		}
	}

	// If there were absolutely no versions, and v0 was requested, accept the master as-is.
	if unversioned && repo.Version == (Version{0, -1, -1}) {
		return data, nil, nil
	}

	if mrefi == 0 || vrefi == 0 {
		return nil, nil, ErrNoVersion
	}

	copy(data[mrefi:mrefj], data[vrefi:vrefj])
	return data, versions, nil
}
<commit_msg>Fix "typo"<commit_after>package main

import (
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"regexp"
	"strconv"
	"strings"
	"text/template"
)

var httpFlag = flag.String("http", ":8080", "Serve HTTP at given address")
var httpsFlag = flag.String("https", "", "Serve HTTPS at given address")
var certFlag = flag.String("cert", "", "Use the provided TLS certificate")
var keyFlag = flag.String("key", "", "Use the provided TLS key")

func main() {
	if err := run(); err != nil {
		fmt.Fprintf(os.Stderr, "error: %v\n", err)
		os.Exit(1)
	}
}

func run() error {
	flag.Parse()
	if len(flag.Args()) > 0 {
		return fmt.Errorf("too many arguments: %s", flag.Args()[0])
	}

	http.HandleFunc("/", handler)

	if *httpFlag == "" && *httpsFlag == "" {
		return fmt.Errorf("must provide -http and/or -https")
	}
	if (*httpsFlag != "" || *certFlag != "" || *keyFlag != "") && (*httpsFlag == "" || *certFlag == "" || *keyFlag == "") {
		return fmt.Errorf("-https -cert and -key must be used together")
	}

	ch := make(chan error, 2)

	if *httpFlag != "" {
		go func() {
			ch <- http.ListenAndServe(*httpFlag, nil)
		}()
	}
	if *httpsFlag != "" {
		go func() {
			ch <- http.ListenAndServeTLS(*httpsFlag, *certFlag, *keyFlag, nil)
		}()
	}
	return <-ch
}

var tmplProxy = template.Must(template.New("").Parse(`
<html>
<head>
<meta name="go-import" content="{{.PkgRoot}} git {{.GitRoot}}">
</head>
<body>
<script>
window.location = "http://godoc.org/{{.PkgPath}}" + window.location.hash;
</script>
</body>
</html>
`))

type Repo struct {
	User       string // username or organization, includes forward slash
	Pkg        string // repository name
	VersionStr string // version string ("v1")
	Path       string // path inside repository
	Compat     bool   // when true, use old format

	Version  Version     // requested version (major only)
	Versions VersionList // available versions
}

func (repo *Repo) GitRoot() string {
	return "https://" + repo.PkgRoot()
}

func (repo *Repo) HubRoot() string {
	if len(repo.User) == 0 {
		return "https://github.com/go-" + repo.Pkg + "/" + repo.Pkg
	}
	return "https://github.com/" + repo.User + repo.Pkg
}

func (repo *Repo) PkgBase() string {
	return "gopkg.in/" + repo.User + repo.Pkg
}

func (repo *Repo) PkgRoot() string {
	if repo.Compat {
		return "gopkg.in/" + repo.User + repo.VersionStr + "/" + repo.Pkg
	}
	return repo.PkgBase() + "." + repo.VersionStr
}

func (repo *Repo) PkgPath() string {
	return repo.PkgRoot() + repo.Path
}

var patternOld = regexp.MustCompile(`^/([a-z0-9][-a-z0-9]+/)?((?:v0|v[1-9][0-9]*)(?:\.0|\.[1-9][0-9]*){0,2})/([a-zA-Z][-a-zA-Z0-9]*)(?:\.git)?((?:/[a-zA-Z][-a-zA-Z0-9]*)*)$`)
var patternNew = regexp.MustCompile(`^/([a-z0-9][-a-z0-9]+/)?([a-zA-Z][-a-zA-Z0-9]*)\.((?:v0|v[1-9][0-9]*)(?:\.0|\.[1-9][0-9]*){0,2})(?:\.git)?((?:/[a-zA-Z][-a-zA-Z0-9]*)*)$`)

func handler(resp http.ResponseWriter, req *http.Request) {
	if req.URL.Path == "/health-check" {
		resp.Write([]byte("ok"))
		return
	}

	log.Printf("%s requested %s", req.RemoteAddr, req.URL)

	if req.URL.Path == "/" {
		resp.Header().Set("Location", "http://labix.org/gopkg.in")
		resp.WriteHeader(http.StatusTemporaryRedirect)
		return
	}

	goget := req.FormValue("go-get") == "1"

	m := patternNew.FindStringSubmatch(req.URL.Path)
	compat := false
	if m == nil {
		m = patternOld.FindStringSubmatch(req.URL.Path)
		if m == nil {
			sendNotFound(resp, "Unsupported URL pattern; see the documentation at gopkg.in for details.")
			return
		}
		m[2], m[3] = m[3], m[2]
		compat = true
	}

	if strings.Contains(m[3], ".") {
		sendNotFound(resp, "Import paths take the major version only (.%s instead of .%s); see docs at gopkg.in for the reasoning.",
			m[3][:strings.Index(m[3], ".")], m[3])
		return
	}

	repo := &Repo{
		User:       m[1],
		Pkg:        m[2],
		VersionStr: m[3],
		Path:       m[4],
		Compat:     compat,
	}

	var ok bool
	repo.Version, ok = parseVersion(repo.VersionStr)
	if !ok {
		sendNotFound(resp, "Version %q improperly considered invalid; please warn the service maintainers.", m[3])
		return
	}

	// // Run this concurrently to avoid waiting later.
	// nameVersioned := nameHasVersion(repo)

	var err error
	var refs []byte
	refs, repo.Versions, err = hackedRefs(repo)
	switch err {
	case nil:
		// repo.GitRoot = "https://" + repo.PkgRoot
		// all ok
	case ErrNoRepo:
		// if <-nameVersioned {
		// 	v := repo.Version.String()
		// 	repo.GitRoot += "-" + v
		// 	repo.HubRoot += "-" + v
		// 	break
		// }
		sendNotFound(resp, "GitHub repository not found at %s", repo.HubRoot())
		return
	case ErrNoVersion:
		v := repo.Version.String()
		if repo.Version.Minor == -1 {
			sendNotFound(resp, `GitHub repository at %s has no branch or tag "%s", "%s.N" or "%s.N.M"`, repo.HubRoot(), v, v, v)
		} else if repo.Version.Patch == -1 {
			sendNotFound(resp, `GitHub repository at %s has no branch or tag "%s" or "%s.N"`, repo.HubRoot(), v, v)
		} else {
			sendNotFound(resp, `GitHub repository at %s has no branch or tag "%s"`, repo.HubRoot(), v)
		}
		return
	default:
		resp.WriteHeader(http.StatusBadGateway)
		resp.Write([]byte(fmt.Sprintf("Cannot obtain refs from GitHub: %v", err)))
		return
	}

	if m[4] == "/git-upload-pack" {
		resp.Header().Set("Location", repo.HubRoot()+"/git-upload-pack")
		resp.WriteHeader(http.StatusMovedPermanently)
		return
	}

	if m[4] == "/info/refs" {
		resp.Header().Set("Content-Type", "application/x-git-upload-pack-advertisement")
		resp.Write(refs)
		return
	}

	resp.Header().Set("Content-Type", "text/html")
	if goget {
		// execute simple template when this is a go-get request
		err = tmplProxy.Execute(resp, repo)
		if err != nil {
			log.Printf("error executing tmplProxy: %s\n", err)
		}
		return
	}

	renderInterface(resp, req, repo)
}

func sendNotFound(resp http.ResponseWriter, msg string, args ...interface{}) {
	if len(args) > 0 {
		msg = fmt.Sprintf(msg, args...)
	}
	resp.WriteHeader(http.StatusNotFound)
	resp.Write([]byte(msg))
}

// TODO Timeouts for these http interactions. Use the new support coming in 1.3.

const refsSuffix = ".git/info/refs?service=git-upload-pack"

// // Obsolete. Drop this.
// func nameHasVersion(repo *Repo) chan bool {
// 	ch := make(chan bool, 1)
// 	go func() {
// 		resp, err := http.Head(repo.HubRoot + "-" + repo.Version.String() + refsSuffix)
// 		if err != nil {
// 			ch <- false
// 			return
// 		}
// 		if resp.Body != nil {
// 			resp.Body.Close()
// 		}
// 		ch <- resp.StatusCode == 200
// 	}()
// 	return ch
// }

var ErrNoRepo = errors.New("repository not found in github")
var ErrNoVersion = errors.New("version reference not found in github")

func hackedRefs(repo *Repo) (data []byte, versions []Version, err error) {
	resp, err := http.Get(repo.HubRoot() + refsSuffix)
	if err != nil {
		return nil, nil, fmt.Errorf("cannot talk to GitHub: %v", err)
	}
	switch resp.StatusCode {
	case 200:
		defer resp.Body.Close()
	case 401, 404:
		return nil, nil, ErrNoRepo
	default:
		return nil, nil, fmt.Errorf("error from GitHub: %v", resp.Status)
	}

	data, err = ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, nil, fmt.Errorf("error reading from GitHub: %v", err)
	}

	var mrefi, mrefj int
	var vrefi, vrefj int
	var vrefv = InvalidVersion
	var unversioned = true

	versions = make([]Version, 0)
	sdata := string(data)
	for i, j := 0, 0; i < len(data); i = j {
		size, err := strconv.ParseInt(sdata[i:i+4], 16, 32)
		if err != nil {
			return nil, nil, fmt.Errorf("cannot parse refs line size: %s", string(data[i:i+4]))
		}
		if size == 0 {
			size = 4
		}
		j = i + int(size)
		if j > len(sdata) {
			return nil, nil, fmt.Errorf("incomplete refs data received from GitHub")
		}
		if sdata[0] == '#' {
			continue
		}

		hashi := i + 4
		hashj := strings.IndexByte(sdata[hashi:j], ' ')
		if hashj < 0 || hashj != 40 {
			continue
		}
		hashj += hashi

		namei := hashj + 1
		namej := strings.IndexAny(sdata[namei:j], "\n\x00")
		if namej < 0 {
			namej = j
		} else {
			namej += namei
		}

		name := sdata[namei:namej]

		if name == "refs/heads/master" {
			mrefi = hashi
			mrefj = hashj
		}

		if strings.HasPrefix(name, "refs/heads/v") || strings.HasPrefix(name, "refs/tags/v") {
			v, ok := parseVersion(name[strings.IndexByte(name, 'v'):])
			if ok && repo.Version.Contains(v) && (!vrefv.IsValid() || vrefv.Less(v)) {
				vrefv = v
				vrefi = hashi
				vrefj = hashj
			}
			if ok {
				unversioned = false
				versions = append(versions, v)
			}
		}
	}

	// If there were absolutely no versions, and v0 was requested, accept the master as-is.
	if unversioned && repo.Version == (Version{0, -1, -1}) {
		return data, nil, nil
	}

	if mrefi == 0 || vrefi == 0 {
		return nil, nil, ErrNoVersion
	}

	copy(data[mrefi:mrefj], data[vrefi:vrefj])
	return data, versions, nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"

	"github.com/ninech/frau-schultz/api"
)

func main() {
	fmt.Println("Hallo, ich bin Frau Schultz!")

	engine := api.GetMainEngine()
	engine.Run(":8080")
}
<commit_msg>Finish requests before shutdown<commit_after>package main

import (
	"context"
	"fmt"
	"log"
	"net/http"
	"os"
	"os/signal"
	"time"

	"github.com/ninech/frau-schultz/api"
)

// DefaultPort defines the app's default HTTP port
const DefaultPort = "8080"

var srv *http.Server

func main() {
	fmt.Println("Hallo, ich bin Frau Schultz!")
	serveRequests()
	waitForQuitSignal()
	log.Println("Frau Schultz sagt auf Wiedersehen ...")
	gracefullyStop(5 * time.Second)
}

func serveRequests() {
	router := api.GetMainEngine()

	srv = &http.Server{
		Addr:    ":" + DefaultPort,
		Handler: router,
	}

	go func() {
		// service connections
		if err := srv.ListenAndServe(); err != nil {
			log.Printf("listen: %s\n", err)
		}
	}()
}

func waitForQuitSignal() {
	quit := make(chan os.Signal)
	signal.Notify(quit, os.Interrupt)
	<-quit
}

func gracefullyStop(timeout time.Duration) {
	ctx, cancel := context.WithTimeout(context.Background(), timeout)
	defer cancel()
	if err := srv.Shutdown(ctx); err != nil {
		log.Fatal("Server Shutdown:", err)
	}
}
<|endoftext|>


<commit_before>// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"bytes"
	"flag"
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"text/tabwriter"

	"github.com/pkg/errors"
	"github.com/sdboyer/gps"
)

const (
	manifestName = "manifest.json"
	lockName     = "lock.json"
)

var (
	depContext *ctx
	verbose    = flag.Bool("v", false, "enable verbose logging")
)

type command interface {
	Name() string           // "foobar"
	Args() string           // "<baz> [quux...]"
	ShortHelp() string      // "Foo the first bar"
	LongHelp() string       // "Foo the first bar meeting the following conditions..."
	Register(*flag.FlagSet) // command-specific flags
	Hidden() bool           // indicates whether the command should be hidden from help output
	Run([]string) error
}

func main() {

	// Build the list of available commands.
	commands := []command{
		&initCommand{},
		&statusCommand{},
		&ensureCommand{},
		&removeCommand{},
		&hashinCommand{},
	}

	usage := func() {
		fmt.Fprintln(os.Stderr, "Usage: dep <command>")
		fmt.Fprintln(os.Stderr)
		fmt.Fprintln(os.Stderr, "Commands:")
		fmt.Fprintln(os.Stderr)
		w := tabwriter.NewWriter(os.Stderr, 0, 4, 2, ' ', 0)
		for _, cmd := range commands {
			if !cmd.Hidden() {
				fmt.Fprintf(w, "\t%s\t%s\n", cmd.Name(), cmd.ShortHelp())
			}
		}
		w.Flush()
		fmt.Fprintln(os.Stderr)
	}

	if len(os.Args) <= 1 || len(os.Args) == 2 && (strings.Contains(strings.ToLower(os.Args[1]), "help") || strings.ToLower(os.Args[1]) == "-h") {
		usage()
		os.Exit(1)
	}

	// Set up the dep context.
	// TODO(pb): can this be deglobalized, pretty please?
	hc, err := newContext()
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
	depContext = hc

	for _, cmd := range commands {
		if name := cmd.Name(); os.Args[1] == name {
			// Build flag set with global flags in there.
			// TODO(pb): can we deglobalize verbose, pretty please?
			fs := flag.NewFlagSet(name, flag.ExitOnError)
			fs.BoolVar(verbose, "v", false, "enable verbose logging")

			// Register the subcommand flags in there, too.
			cmd.Register(fs)

			// Override the usage text to something nicer.
			resetUsage(fs, cmd.Name(), cmd.Args(), cmd.LongHelp())

			// Parse the flags the user gave us.
			if err := fs.Parse(os.Args[2:]); err != nil {
				fs.Usage()
				os.Exit(1)
			}

			// Run the command with the post-flag-processing args.
			if err := cmd.Run(fs.Args()); err != nil {
				fmt.Fprintf(os.Stderr, "%v\n", err)
				os.Exit(1)
			}

			// Easy peasy livin' breezy.
			return
		}
	}

	fmt.Fprintf(os.Stderr, "%s: no such command\n", os.Args[1])
	usage()
	os.Exit(1)
}

func resetUsage(fs *flag.FlagSet, name, args, longHelp string) {
	var (
		hasFlags   bool
		flagBlock  bytes.Buffer
		flagWriter = tabwriter.NewWriter(&flagBlock, 0, 4, 2, ' ', 0)
	)
	fs.VisitAll(func(f *flag.Flag) {
		hasFlags = true
		// Default-empty string vars should read "(default: <none>)"
		// rather than the comparatively ugly "(default: )".
		defValue := f.DefValue
		if defValue == "" {
			defValue = "<none>"
		}
		fmt.Fprintf(flagWriter, "\t-%s\t%s (default: %s)\n", f.Name, f.Usage, defValue)
	})
	flagWriter.Flush()
	fs.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage: dep %s %s\n", name, args)
		fmt.Fprintln(os.Stderr)
		fmt.Fprintln(os.Stderr, strings.TrimSpace(longHelp))
		fmt.Fprintln(os.Stderr)
		if hasFlags {
			fmt.Fprintln(os.Stderr, "Flags:")
			fmt.Fprintln(os.Stderr)
			fmt.Fprintln(os.Stderr, flagBlock.String())
		}
	}
}

var (
	errProjectNotFound = errors.New("could not find project manifest.json, use dep init to initiate a manifest")
)

func findProjectRootFromWD() (string, error) {
	path, err := os.Getwd()
	if err != nil {
		return "", fmt.Errorf("could not get working directory: %s", err)
	}
	return findProjectRoot(path)
}

// search upwards looking for a manifest file until we get to the root of the
// filesystem
func findProjectRoot(from string) (string, error) {
	for {
		mp := filepath.Join(from, manifestName)

		_, err := os.Stat(mp)
		if err == nil {
			return from, nil
		}
		if !os.IsNotExist(err) {
			// Some err other than non-existence - return that out
			return "", err
		}

		parent := filepath.Dir(from)
		if parent == from {
			return "", errProjectNotFound
		}
		from = parent
	}
}

type project struct {
	// absroot is the absolute path to the root directory of the project.
	absroot string
	// importroot is the import path of the project's root directory.
	importroot gps.ProjectRoot
	m          *manifest
	l          *lock
}

// makeParams is a simple helper to create a gps.SolveParameters without setting
// any nils incorrectly.
func (p *project) makeParams() gps.SolveParameters {
	params := gps.SolveParameters{
		RootDir: p.absroot,
	}

	if p.m != nil {
		params.Manifest = p.m
	}

	if p.l != nil {
		params.Lock = p.l
	}

	return params
}

func logf(format string, args ...interface{}) {
	// TODO: something else?
	fmt.Fprintf(os.Stderr, "dep: "+format+"\n", args...)
}

func vlogf(format string, args ...interface{}) {
	if !*verbose {
		return
	}
	logf(format, args...)
}
<commit_msg>doc: add godoc to the binary<commit_after>// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Command dep is a prototype dependency management tool.
package main

import (
	"bytes"
	"flag"
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"text/tabwriter"

	"github.com/pkg/errors"
	"github.com/sdboyer/gps"
)

const (
	manifestName = "manifest.json"
	lockName     = "lock.json"
)

var (
	depContext *ctx
	verbose    = flag.Bool("v", false, "enable verbose logging")
)

type command interface {
	Name() string           // "foobar"
	Args() string           // "<baz> [quux...]"
	ShortHelp() string      // "Foo the first bar"
	LongHelp() string       // "Foo the first bar meeting the following conditions..."
	Register(*flag.FlagSet) // command-specific flags
	Hidden() bool           // indicates whether the command should be hidden from help output
	Run([]string) error
}

func main() {

	// Build the list of available commands.
	commands := []command{
		&initCommand{},
		&statusCommand{},
		&ensureCommand{},
		&removeCommand{},
		&hashinCommand{},
	}

	usage := func() {
		fmt.Fprintln(os.Stderr, "Usage: dep <command>")
		fmt.Fprintln(os.Stderr)
		fmt.Fprintln(os.Stderr, "Commands:")
		fmt.Fprintln(os.Stderr)
		w := tabwriter.NewWriter(os.Stderr, 0, 4, 2, ' ', 0)
		for _, cmd := range commands {
			if !cmd.Hidden() {
				fmt.Fprintf(w, "\t%s\t%s\n", cmd.Name(), cmd.ShortHelp())
			}
		}
		w.Flush()
		fmt.Fprintln(os.Stderr)
	}

	if len(os.Args) <= 1 || len(os.Args) == 2 && (strings.Contains(strings.ToLower(os.Args[1]), "help") || strings.ToLower(os.Args[1]) == "-h") {
		usage()
		os.Exit(1)
	}

	// Set up the dep context.
	// TODO(pb): can this be deglobalized, pretty please?
	hc, err := newContext()
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
	depContext = hc

	for _, cmd := range commands {
		if name := cmd.Name(); os.Args[1] == name {
			// Build flag set with global flags in there.
			// TODO(pb): can we deglobalize verbose, pretty please?
			fs := flag.NewFlagSet(name, flag.ExitOnError)
			fs.BoolVar(verbose, "v", false, "enable verbose logging")

			// Register the subcommand flags in there, too.
			cmd.Register(fs)

			// Override the usage text to something nicer.
			resetUsage(fs, cmd.Name(), cmd.Args(), cmd.LongHelp())

			// Parse the flags the user gave us.
			if err := fs.Parse(os.Args[2:]); err != nil {
				fs.Usage()
				os.Exit(1)
			}

			// Run the command with the post-flag-processing args.
			if err := cmd.Run(fs.Args()); err != nil {
				fmt.Fprintf(os.Stderr, "%v\n", err)
				os.Exit(1)
			}

			// Easy peasy livin' breezy.
			return
		}
	}

	fmt.Fprintf(os.Stderr, "%s: no such command\n", os.Args[1])
	usage()
	os.Exit(1)
}

func resetUsage(fs *flag.FlagSet, name, args, longHelp string) {
	var (
		hasFlags   bool
		flagBlock  bytes.Buffer
		flagWriter = tabwriter.NewWriter(&flagBlock, 0, 4, 2, ' ', 0)
	)
	fs.VisitAll(func(f *flag.Flag) {
		hasFlags = true
		// Default-empty string vars should read "(default: <none>)"
		// rather than the comparatively ugly "(default: )".
		defValue := f.DefValue
		if defValue == "" {
			defValue = "<none>"
		}
		fmt.Fprintf(flagWriter, "\t-%s\t%s (default: %s)\n", f.Name, f.Usage, defValue)
	})
	flagWriter.Flush()
	fs.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage: dep %s %s\n", name, args)
		fmt.Fprintln(os.Stderr)
		fmt.Fprintln(os.Stderr, strings.TrimSpace(longHelp))
		fmt.Fprintln(os.Stderr)
		if hasFlags {
			fmt.Fprintln(os.Stderr, "Flags:")
			fmt.Fprintln(os.Stderr)
			fmt.Fprintln(os.Stderr, flagBlock.String())
		}
	}
}

var (
	errProjectNotFound = errors.New("could not find project manifest.json, use dep init to initiate a manifest")
)

func findProjectRootFromWD() (string, error) {
	path, err := os.Getwd()
	if err != nil {
		return "", fmt.Errorf("could not get working directory: %s", err)
	}
	return findProjectRoot(path)
}

// search upwards looking for a manifest file until we get to the root of the
// filesystem
func findProjectRoot(from string) (string, error) {
	for {
		mp := filepath.Join(from, manifestName)

		_, err := os.Stat(mp)
		if err == nil {
			return from, nil
		}
		if !os.IsNotExist(err) {
			// Some err other than non-existence - return that out
			return "", err
		}

		parent := filepath.Dir(from)
		if parent == from {
			return "", errProjectNotFound
		}
		from = parent
	}
}

type project struct {
	// absroot is the absolute path to the root directory of the project.
	absroot string
	// importroot is the import path of the project's root directory.
	importroot gps.ProjectRoot
	m          *manifest
	l          *lock
}

// makeParams is a simple helper to create a gps.SolveParameters without setting
// any nils incorrectly.
func (p *project) makeParams() gps.SolveParameters {
	params := gps.SolveParameters{
		RootDir: p.absroot,
	}

	if p.m != nil {
		params.Manifest = p.m
	}

	if p.l != nil {
		params.Lock = p.l
	}

	return params
}

func logf(format string, args ...interface{}) {
	// TODO: something else?
	fmt.Fprintf(os.Stderr, "dep: "+format+"\n", args...)
}

func vlogf(format string, args ...interface{}) {
	if !*verbose {
		return
	}
	logf(format, args...)
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"runtime/pprof"
)

var (
	envPath = os.Getenv("PATH")
)

var (
	gClientID      int
	gHostname      string
	gLastDirPath   string
	gSelectionPath string
	gSocketProt    string
	gSocketPath    string
	gLogPath       string
	gServerLogPath string
)

func init() {
	var err error

	gHostname, err = os.Hostname()
	if err != nil {
		log.Printf("hostname: %s", err)
	}
}

func startServer() {
	cmd := exec.Command(os.Args[0], "-server")
	if err := cmd.Start(); err != nil {
		log.Printf("starting server: %s", err)
	}
}

func main() {
	showDoc := flag.Bool("doc", false, "show documentation")
	remoteCmd := flag.String("remote", "", "send remote command to server")
	serverMode := flag.Bool("server", false, "start server (automatic)")
	cpuprofile := flag.String("cpuprofile", "", "path to the file to write the cpu profile")
	flag.StringVar(&gLastDirPath, "last-dir-path", "", "path to the file to write the last dir on exit (to use for cd)")
	flag.StringVar(&gSelectionPath, "selection-path", "", "path to the file to write selected files on open (to use as open file dialog)")

	flag.Parse()

	gSocketProt = gDefaultSocketProt
	gSocketPath = gDefaultSocketPath

	if *showDoc {
		fmt.Print(genDocString)
		return
	}

	if *remoteCmd != "" {
		if err := sendRemote(*remoteCmd); err != nil {
			log.Fatalf("remote command: %s", err)
		}
		return
	}

	if *cpuprofile != "" {
		f, err := os.Create(*cpuprofile)
		if err != nil {
			log.Fatalf("could not create CPU profile: %s", err)
		}
		if err := pprof.StartCPUProfile(f); err != nil {
			log.Fatalf("could not start CPU profile: %s", err)
		}
		defer pprof.StopCPUProfile()
	}

	if *serverMode {
		gServerLogPath = filepath.Join(os.TempDir(), fmt.Sprintf("lf.%s.server.log", gUser.Username))
		serve()
	} else {
		// TODO: check if the socket is working
		if _, err := os.Stat(gSocketPath); os.IsNotExist(err) {
			startServer()
		}

		gClientID = 1000
		gLogPath = filepath.Join(os.TempDir(), fmt.Sprintf("lf.%s.%d.log", gUser.Username, gClientID))
		for _, err := os.Stat(gLogPath); err == nil; _, err = os.Stat(gLogPath) {
			gClientID++
			gLogPath = filepath.Join(os.TempDir(), fmt.Sprintf("lf.%s.%d.log", gUser.Username, gClientID))
		}

		client()
	}
}
<commit_msg>change directory to the first argument on startup<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"runtime/pprof"
)

var (
	envPath = os.Getenv("PATH")
)

var (
	gClientID      int
	gHostname      string
	gLastDirPath   string
	gSelectionPath string
	gSocketProt    string
	gSocketPath    string
	gLogPath       string
	gServerLogPath string
)

func init() {
	var err error

	gHostname, err = os.Hostname()
	if err != nil {
		log.Printf("hostname: %s", err)
	}
}

func startServer() {
	cmd := exec.Command(os.Args[0], "-server")
	if err := cmd.Start(); err != nil {
		log.Printf("starting server: %s", err)
	}
}

func main() {
	showDoc := flag.Bool("doc", false, "show documentation")
	remoteCmd := flag.String("remote", "", "send remote command to server")
	serverMode := flag.Bool("server", false, "start server (automatic)")
	cpuprofile := flag.String("cpuprofile", "", "path to the file to write the cpu profile")
	flag.StringVar(&gLastDirPath, "last-dir-path", "", "path to the file to write the last dir on exit (to use for cd)")
	flag.StringVar(&gSelectionPath, "selection-path", "", "path to the file to write selected files on open (to use as open file dialog)")

	flag.Parse()

	gSocketProt = gDefaultSocketProt
	gSocketPath = gDefaultSocketPath

	switch flag.NArg() {
	case 0:
	case 1:
		dir := flag.Arg(0)
		if err := os.Chdir(dir); err != nil {
			fmt.Fprintf(os.Stderr, "%s\n", err)
			os.Exit(2)
		}
	default:
		fmt.Fprintf(os.Stderr, "only single directory is allowed\n")
		os.Exit(2)
	}

	if *showDoc {
		fmt.Print(genDocString)
		return
	}

	if *remoteCmd != "" {
		if err := sendRemote(*remoteCmd); err != nil {
			log.Fatalf("remote command: %s", err)
		}
		return
	}

	if *cpuprofile != "" {
		f, err := os.Create(*cpuprofile)
		if err != nil {
			log.Fatalf("could not create CPU profile: %s", err)
		}
		if err := pprof.StartCPUProfile(f); err != nil {
			log.Fatalf("could not start CPU profile: %s", err)
		}
		defer pprof.StopCPUProfile()
	}

	if *serverMode {
		gServerLogPath = filepath.Join(os.TempDir(), fmt.Sprintf("lf.%s.server.log", gUser.Username))
		serve()
	} else {
		// TODO: check if the socket is working
		if _, err := os.Stat(gSocketPath); os.IsNotExist(err) {
			startServer()
		}

		gClientID = 1000
		gLogPath = filepath.Join(os.TempDir(), fmt.Sprintf("lf.%s.%d.log", gUser.Username, gClientID))
		for _, err := os.Stat(gLogPath); err == nil; _, err = os.Stat(gLogPath) {
			gClientID++
			gLogPath = filepath.Join(os.TempDir(), fmt.Sprintf("lf.%s.%d.log", gUser.Username, gClientID))
		}

		client()
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"encoding/csv"
	"fmt"
	"io"
	"log"
	"net"
	"strings"
	"time"
)

type Program struct {
	URL      string
	Duration time.Duration
}

// Loads a list of programs.
// A program consists of a list things to display on the rotator along
// with a number of seconds to display each one before moving on.
func loadProgramList() []Program {
	var list []Program

	webpages := `"http://wsbtv.com","10s"
"http://slashdot.org","10s"
`

	r := csv.NewReader(strings.NewReader(webpages))

	for {
		var p Program
		record, err := r.Read()
		if err == io.EOF {
			fmt.Printf("Finished loading programs.\n\n")
			break
		}
		if err != nil {
			log.Fatal(err)
		}
		p.URL = record[0]
		p.Duration, err = time.ParseDuration(record[1])
		fmt.Printf("Loaded program %s to show for %s.\n", p.URL, p.Duration)
		list = append(list, p)
	}

	return list
}

func runProgram(program Program) {

	conn, err := net.Dial("tcp", "localhost:32000")
	if err != nil {
		fmt.Println("Error making network connection")
		return
	}
	fmt.Printf("Running program: %s for %s\n", program.URL, program.Duration)
	fmt.Fprintf(conn, "window.location='%s'\n", program.URL)
	status, err := bufio.NewReader(conn).ReadString('\n')
	fmt.Printf("%s", status)
	time.Sleep(program.Duration)
}

func main() {

	pl := loadProgramList()
	for {
		for _, p := range pl {
			runProgram(p)
		}
		fmt.Printf("Looping back to beginning\n\n")
	}
}
<commit_msg>Added Viper basic config.  Added 30s sleep on network connection failure.<commit_after>package main

import (
	"bufio"
	"encoding/csv"
	"fmt"
	"io"
	"log"
	"net"
	"os"
	"strings"
	"time"

	"github.com/spf13/viper"
)

type Program struct {
	URL      string
	Duration time.Duration
}

// Loads a list of programs.
// A program consists of a list things to display on the rotator along
// with a number of seconds to display each one before moving on.
func loadProgramList() []Program {
	var list []Program

	webpages := `"http://wsbtv.com","10s"
"http://slashdot.org","10s"
`

	r := csv.NewReader(strings.NewReader(webpages))

	for {
		var p Program
		record, err := r.Read()
		if err == io.EOF {
			fmt.Printf("Finished loading programs.\n\n")
			break
		}
		if err != nil {
			log.Fatal(err)
		}
		p.URL = record[0]
		p.Duration, err = time.ParseDuration(record[1])
		fmt.Printf("Loaded program %s to show for %s.\n", p.URL, p.Duration)
		list = append(list, p)
	}

	return list
}

func runProgram(program Program) {

	ip := viper.Get("IP")
	port := viper.GetInt("PORT")

	constr := fmt.Sprintf("%s:%d", ip, port)

	conn, err := net.Dial("tcp", constr)
	if err != nil {
		fmt.Printf("Error making network connection to: %s\n", constr)
		fmt.Println("Pausing for 30s")
		time.Sleep(30 * time.Second) // wait 30 seconds to slow retries
		return
	}

	fmt.Printf("Running program: %s for %s\n", program.URL, program.Duration)
	fmt.Fprintf(conn, "window.location='%s'\n", program.URL)
	status, err := bufio.NewReader(conn).ReadString('\n')
	fmt.Printf("%s", status)
	time.Sleep(program.Duration)
}

// InitializeConfig loads our configuration using Viper package.
func InitializeConfig() {

	viper.SetConfigType("yaml")
	// Set config file
	viper.SetConfigName("config")

	// Add config path
	//	viper.AddConfigPath("$HOME/.gorotator")
	viper.AddConfigPath(".")

	// Read in the config
	err := viper.ReadInConfig() // Find and read the config file
	if err != nil {             // Handle errors reading the config file
		panic(fmt.Errorf("Fatal error config file: %s \n", err))
	}

	// Load default settings
	viper.SetDefault("debug", false)

	viper.SetEnvPrefix("gorotator") // will be uppercased automatically
	viper.BindEnv("debug")
	viper.BindEnv("ip")
	viper.BindEnv("port")

	// Do some flag handling and any complicated config logic
	if !viper.IsSet("ip") || !viper.IsSet("port") {
		fmt.Println("Configuration error.  Both IP and PORT must be set via either config or environment.")
		os.Exit(1)
	}

}

func main() {

	InitializeConfig()

	pl := loadProgramList()
	for {
		for _, p := range pl {
			runProgram(p)
		}
		fmt.Printf("Looping back to beginning\n\n")
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"

	"github.com/chiepomme/chienote/convert"
	"github.com/chiepomme/chienote/sync"
	"github.com/spf13/cobra"
)

var cfg *config

func main() {
	var cmdInit = &cobra.Command{
		Use:   "init",
		Short: "Initialize your configuration file",
		Run: func(cmd *cobra.Command, args []string) {
			if err := initialize(); err != nil {
				fmt.Println(err)
				os.Exit(-1)
			}
		},
	}

	var cmdSync = &cobra.Command{
		Use:   "sync",
		Short: "Sync local cache and evernote notes",
		Run: func(cmd *cobra.Command, args []string) {
			cfg := loadConfig()
			if err := sync.Sync(cacheRoot, noteCacheDirName, resourceCacheDirName, cfg.ClientKey, cfg.ClientSecret, cfg.DeveloperToken, cfg.Sandbox, cfg.NotebookName); err != nil {
				fmt.Println(err)
				os.Exit(-1)
			}
		},
	}

	var cmdConvert = &cobra.Command{
		Use:   "convert",
		Short: "Convert local cache to post files",
		Run: func(cmd *cobra.Command, args []string) {
			loadConfig()
			if err := convert.Convert(cacheRoot, noteCacheDirName, resourceCacheDirName, ".", postDirName, resourceDirName, true); err != nil {
				fmt.Println(err)
				os.Exit(-1)
			}
		},
	}

	var rootCmd = &cobra.Command{Use: "chienote", Long: "Sync your evernote notebook to your jekyll directory. Execute chienote at your jekyll root."}
	rootCmd.AddCommand(cmdInit, cmdSync, cmdConvert)
	rootCmd.Execute()
}

func loadConfig() *config {
	cfg, err := getConfig()
	if err != nil {
		fmt.Println("configuration file load error")
		fmt.Println("it is recommended to execute init command")
		fmt.Println(err)
		os.Exit(-1)
	}
	return cfg
}
<commit_msg>Print more meaningful errors<commit_after>package main

import (
	"fmt"
	"os"

	"github.com/chiepomme/chienote/convert"
	"github.com/chiepomme/chienote/sync"
	"github.com/spf13/cobra"
)

var cfg *config

func main() {
	var cmdInit = &cobra.Command{
		Use:   "init",
		Short: "Initialize your configuration file",
		Run: func(cmd *cobra.Command, args []string) {
			if err := initialize(); err != nil {
				fmt.Printf("%+v\n", err)
				os.Exit(-1)
			}
		},
	}

	var cmdSync = &cobra.Command{
		Use:   "sync",
		Short: "Sync local cache and evernote notes",
		Run: func(cmd *cobra.Command, args []string) {
			cfg := loadConfig()
			if err := sync.Sync(cacheRoot, noteCacheDirName, resourceCacheDirName, cfg.ClientKey, cfg.ClientSecret, cfg.DeveloperToken, cfg.Sandbox, cfg.NotebookName); err != nil {
				fmt.Printf("%+v\n", err)
				os.Exit(-1)
			}
		},
	}

	var cmdConvert = &cobra.Command{
		Use:   "convert",
		Short: "Convert local cache to post files",
		Run: func(cmd *cobra.Command, args []string) {
			loadConfig()
			if err := convert.Convert(cacheRoot, noteCacheDirName, resourceCacheDirName, ".", postDirName, resourceDirName, true); err != nil {
				fmt.Printf("%+v\n", err)
				os.Exit(-1)
			}
		},
	}

	var rootCmd = &cobra.Command{Use: "chienote", Long: "Sync your evernote notebook to your jekyll directory. Execute chienote at your jekyll root."}
	rootCmd.AddCommand(cmdInit, cmdSync, cmdConvert)
	rootCmd.Execute()
}

func loadConfig() *config {
	cfg, err := getConfig()
	if err != nil {
		fmt.Println("configuration file load error")
		fmt.Println("it is recommended to execute init command")
		fmt.Printf("%+v", err)
		os.Exit(-1)
	}
	return cfg
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"strings"
)

// FIXME: use -ldflags to automatically get the Version ?
// go build -ldflags "-X main.Version 0.1.`date -u +.%Y%m%d%.H%M%S`" main.go

const Version = "0.1"

const tmpl = `## AUTOMATICALLY generated by mk.

## simple makefile to log workflow
.PHONY: all test clean build install

GOFLAGS ?= $(GOFLAGS:)

all: install test

build:
	@go build -v $(GOFLAGS) ./...

install:
	@go get -v $(GOFLAGS) ./...

gen:
	@go generate $(GOFLAGS) ./...

test: install
	@go test $(GOFLAGS) ./...

bench: install
	@go test -run=NONE -bench=. $(GOFLAGS) ./...

clean:
	@go clean $(GOFLAGS) -i ./...

## EOF
`

const mkfname = ".makefile-mkgo.mk"

var (
	verbose  = flag.Bool("v", false, "enable verbose output")
	makefile = flag.String("f", mkfname, "alternate Makefile")
	race     = flag.Bool("race", false, "enable build with race detector")
	compiler = flag.String("compiler", "gc", "go compiler to use (gc,gccgo,llgo)")

	show        = flag.Bool("show", false, "dump the Makefile mk will use on STDOUT")
	showDefault = flag.Bool("show-default", false, "dump the default Makefile-mk on STDOUT")
	version     = flag.Bool("version", false, "dump mk's version")
)

func main() {
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, `mk - a simple makefile generator for Go packages.

Usage of mk:

$ mk [options] [target-name]

Examples:

$ mk
$ mk -f Makefile-my.mk
$ mk install

Options:
`)
		flag.PrintDefaults()
	}

	flag.Parse()

	if *version {
		fmt.Fprintf(os.Stdout, "mk version: %v\n", Version)
		os.Exit(0)
	}

	if *showDefault {
		fmt.Fprintf(os.Stdout, tmpl)
		os.Exit(0)
	}

	// detect if there is a Makefile in the current directory.
	// use it instead (if user didn't specify an alternate Makefile)
	if *makefile == mkfname {
		if _, err := os.Stat("Makefile"); err == nil {
			*makefile = "Makefile"
		}
	}

	rc := run()
	os.Exit(rc)
}

func run() int {
	var err error

	if *makefile == mkfname {
		err = ioutil.WriteFile(*makefile, []byte(tmpl), 0644)
		defer os.Remove(*makefile)
		if err != nil {
			fmt.Fprintf(os.Stderr, "**error** creating file [%s]: %v\n", *makefile, err)
			return 1
		}
	}

	if *show {
		mkfile, err := os.Open(*makefile)
		if err != nil {
			fmt.Fprintf(os.Stderr, "**error** opening file [%s]: %v\n", *makefile, err)
			return 1
		}
		defer mkfile.Close()
		_, err = io.Copy(os.Stdout, mkfile)
		return 0
	}

	cmdargs := make([]string, 0, flag.NArg())
	cmdargs = append(cmdargs, "-f", *makefile)
	goflags := os.Getenv("GOFLAGS")
	if *verbose {
		goflags += " -v"
	}
	if *race {
		goflags += " -race"
	}
	goflags += fmt.Sprintf(" -compiler=%s", *compiler)

	os.Setenv("GOFLAGS", goflags)

	cmdargs = append(cmdargs, flag.Args()...)

	cmd := exec.Command("make", cmdargs...)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	err = cmd.Run()
	if err != nil {
		fmt.Fprintf(os.Stderr, "**error** running make %s: %v\n",
			strings.Join(cmdargs, " "),
			err,
		)
		return 1
	}

	return 0
}
<commit_msg>mk: v0.2.0<commit_after>package main

import (
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"strings"
)

// FIXME: use -ldflags to automatically get the Version ?
// go build -ldflags "-X main.Version 0.1.`date -u +.%Y%m%d%.H%M%S`" main.go

const Version = "0.2.0"

const tmpl = `## AUTOMATICALLY generated by mk.

## simple makefile to log workflow
.PHONY: all test clean build install

GOFLAGS ?= $(GOFLAGS:)

all: install test

build:
	@go build -v $(GOFLAGS) ./...

install:
	@go get -v $(GOFLAGS) ./...

gen:
	@go generate $(GOFLAGS) ./...

test: install
	@go test $(GOFLAGS) ./...

bench: install
	@go test -run=NONE -bench=. $(GOFLAGS) ./...

clean:
	@go clean $(GOFLAGS) -i ./...

## EOF
`

const mkfname = ".makefile-mkgo.mk"

var (
	verbose  = flag.Bool("v", false, "enable verbose output")
	makefile = flag.String("f", mkfname, "alternate Makefile")
	race     = flag.Bool("race", false, "enable build with race detector")
	compiler = flag.String("compiler", "gc", "go compiler to use (gc,gccgo,llgo)")

	show        = flag.Bool("show", false, "dump the Makefile mk will use on STDOUT")
	showDefault = flag.Bool("show-default", false, "dump the default Makefile-mk on STDOUT")
	version     = flag.Bool("version", false, "dump mk's version")
)

func main() {
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, `mk - a simple makefile generator for Go packages.

Usage of mk:

$ mk [options] [target-name]

Examples:

$ mk
$ mk -f Makefile-my.mk
$ mk install

Options:
`)
		flag.PrintDefaults()
	}

	flag.Parse()

	if *version {
		fmt.Fprintf(os.Stdout, "mk version: %v\n", Version)
		os.Exit(0)
	}

	if *showDefault {
		fmt.Fprintf(os.Stdout, tmpl)
		os.Exit(0)
	}

	// detect if there is a Makefile in the current directory.
	// use it instead (if user didn't specify an alternate Makefile)
	if *makefile == mkfname {
		if _, err := os.Stat("Makefile"); err == nil {
			*makefile = "Makefile"
		}
	}

	rc := run()
	os.Exit(rc)
}

func run() int {
	var err error

	if *makefile == mkfname {
		err = ioutil.WriteFile(*makefile, []byte(tmpl), 0644)
		defer os.Remove(*makefile)
		if err != nil {
			fmt.Fprintf(os.Stderr, "**error** creating file [%s]: %v\n", *makefile, err)
			return 1
		}
	}

	if *show {
		mkfile, err := os.Open(*makefile)
		if err != nil {
			fmt.Fprintf(os.Stderr, "**error** opening file [%s]: %v\n", *makefile, err)
			return 1
		}
		defer mkfile.Close()
		_, err = io.Copy(os.Stdout, mkfile)
		return 0
	}

	cmdargs := make([]string, 0, flag.NArg())
	cmdargs = append(cmdargs, "-f", *makefile)
	goflags := os.Getenv("GOFLAGS")
	if *verbose {
		goflags += " -v"
	}
	if *race {
		goflags += " -race"
	}
	goflags += fmt.Sprintf(" -compiler=%s", *compiler)

	os.Setenv("GOFLAGS", goflags)

	cmdargs = append(cmdargs, flag.Args()...)

	cmd := exec.Command("make", cmdargs...)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	err = cmd.Run()
	if err != nil {
		fmt.Fprintf(os.Stderr, "**error** running make %s: %v\n",
			strings.Join(cmdargs, " "),
			err,
		)
		return 1
	}

	return 0
}
<|endoftext|>


<commit_before>package main

import (
  "fmt"
  "time"
  "io/ioutil"
  "launchpad.net/goamz/aws"
  "launchpad.net/goamz/s3"
)

var (
  bucketName = "pa-hrsuite-production"
  basedir = "/tmp/"
  keybase = "606/docs/"
  doclist = []string{"100001.pdf","100009.pdf","100030.pdf","100035.pdf"}
)

func getFile(bucket *s3.Bucket, docname string, c chan int) {
  s3key := keybase + docname
  data, err := bucket.Get(s3key)
  if err != nil { panic(err) }

  path := "/tmp/"+docname
  err = ioutil.WriteFile(path, data, 0644)
  if err != nil { panic(err) }
  c <- len(data)

}

func connect() *s3.Bucket {
  auth, err := aws.EnvAuth()
  if err != nil { panic(err) }
  s := s3.New(auth, aws.USEast)
  return s.Bucket(bucketName)
}

func printSummary(start time.Time, bytes int){
  elapsed := time.Since(start)
  seconds := elapsed.Seconds()
  mbps := float64(bytes) / 1024 / 1024 / seconds
  fmt.Printf("got %d bytes over %d files in %f secs (%f MB/s)\n",
             bytes, len(doclist), seconds, mbps)
}

func main() {

  start := time.Now()
  bucket := connect()
  c := make(chan int)
  for _,doc := range doclist{
    go getFile(bucket,doc,c)
  }

  totalBytes := 0
  for _,doc := range doclist{
    recieved := <-c
    fmt.Printf("%s was %d bytes\n", doc,recieved)
    totalBytes += recieved
  }
  printSummary(start,totalBytes)

}
<commit_msg>add verbose flag<commit_after>package main

import (
  "flag"
  "fmt"
  "time"
  "io/ioutil"
  "launchpad.net/goamz/aws"
  "launchpad.net/goamz/s3"
)

var (
  verbose bool
  bucketName = "pa-hrsuite-production"
  basedir = "/tmp/"
  keybase = "606/docs/"
  doclist = []string{"100001.pdf","100009.pdf","100030.pdf","100035.pdf",
                     "100035.pdf","100037.pdf","100038.pdf","100093.pdf",}
)

func init(){
  flag.BoolVar(&verbose, "v", false, "Display extra data")
}

func getFile(bucket *s3.Bucket, docname string, c chan int) {
  s3key := keybase + docname
  data, err := bucket.Get(s3key)
  if err != nil { panic(err) }

  path := "/tmp/"+docname
  err = ioutil.WriteFile(path, data, 0644)
  if err != nil { panic(err) }
  c <- len(data)

}

func connect() *s3.Bucket {
  auth, err := aws.EnvAuth()
  if err != nil { panic(err) }
  s := s3.New(auth, aws.USEast)
  return s.Bucket(bucketName)
}

func printSummary(start time.Time, bytes int){
  elapsed := time.Since(start)
  seconds := elapsed.Seconds()
  mbps := float64(bytes) / 1024 / 1024 / seconds
  fmt.Printf("got %d bytes over %d files in %f secs (%f MB/s)\n",
             bytes, len(doclist), seconds, mbps)
}

func main() {

  flag.Parse()
  start := time.Now()
  bucket := connect()
  c := make(chan int)
  for _,doc := range doclist{
    go getFile(bucket,doc,c)
  }

  totalBytes := 0
  for _,doc := range doclist{
    recieved := <-c
    if verbose{
      fmt.Printf("%s was %d bytes\n", doc,recieved)
    }
    totalBytes += recieved
  }
  printSummary(start,totalBytes)

}
<|endoftext|>


<commit_before>
package main

import (
	"fmt"
	"net/http"
	"time"
	)

func main() {
	fileserver := http.FileServer(http.Dir("/opt/htdocs"))

	srv := &http.Server{
		Handler: fileserver,
		ReadTimeout: 30*time.Second,
		WriteTimeout: 30*time.Second,
	}
	fmt.Printf("Listening on port 80...\n")
	err := srv.ListenAndServe()
	if err != nil {
		panic("ListenAndServe: " + err.Error())
	}

}

<commit_msg>Added flag for command line options<commit_after>
package main

import (
	"fmt"
	"net/http"
	"time"
	"flag"
	)

func main() {
	var port *int = flag.Int("port", 8080, "Port to listen on. Default=8080")
	var path *string = flag.String("path", "./", "Path to serve files from.  Default=./")

	fileserver := http.FileServer(http.Dir(*path))

	srv := &http.Server{
		Addr: fmt.Sprintf(":%d", *port),
		Handler: fileserver,
		ReadTimeout: 30*time.Second,
		WriteTimeout: 30*time.Second,
	}
	fmt.Printf("Listening on port %d\n", *port)
	fmt.Printf("Serving from: %s\n", *path)
	err := srv.ListenAndServe()
	if err != nil {
		panic("ListenAndServe: " + err.Error())
	}

}

<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"html/template"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"net/textproto"
	"os"
	"strconv"

	"github.com/Omar-H/goimage/util"
	"github.com/gorilla/csrf"
	"github.com/gorilla/mux"
)

// Data parsed to the ViewHandler's template
type ViewData struct {
	Id       string
	ImageUrl string
	Ext      string
}

// Parsed JSON config
type Config struct {
	Port              int      `json:"port"`
	Secure            bool     `json:"secure"`
	AuthKey           string   `json:"32-byte-auth-key"`
	AllowedMimeTypes  []string `json:"allowed-mime-types"`
	AllowedExtensions []string `json:"allowed-extensions"`
	ImageNameLength   int      `json:"image-name-length"`
	MaxFileSize       int64    `json:"max-file-size"`
	ImageDirectory    string   `json:"image-directory"`
	TemplateDirectory string   `json:"template-directory"`
	PublicDirectory   string   `json:"public-directory"`
	ImageUrl          string   `json:"image-url"`
	CSRF              bool     `json:"csrf"`
}

var config Config

func main() {
	jsonFiles, err := ioutil.ReadFile("./config.json")
	if err != nil {
		log.Fatal(err)
		return
	}
	json.Unmarshal(jsonFiles, &config)

	CSRF := csrf.Protect(
		[]byte(config.AuthKey),
		csrf.RequestHeader("X-CSRF-Token"),
		csrf.FieldName("_csrf"),
		csrf.Secure(config.Secure),
	)
	r := mux.NewRouter()
	err = os.MkdirAll(config.TemplateDirectory, 644)
	if err != nil {
		log.Fatal("Unable to create Template Directory")
	}
	err = os.MkdirAll(config.PublicDirectory, 644)
	if err != nil {
		log.Fatal("Unable to create Public Directory")
	}
	err = os.MkdirAll(config.ImageDirectory, 644)
	if err != nil {
		log.Fatal("Unable to create Image Directory")
	}

	templates := template.Must(template.ParseGlob(config.TemplateDirectory + "*.html"))

	r.HandleFunc("/{id}/", ViewHandler(templates)).Methods("GET")
	r.HandleFunc("/upload/", UploadHandler).Methods("POST")
	r.PathPrefix("/").HandlerFunc(RootHandler(templates)).Methods("GET")

	log.Print("Listening on port " + strconv.Itoa(config.Port))
	if config.CSRF {
		log.Fatal(http.ListenAndServe(":"+strconv.Itoa(config.Port), CSRF(r)))
	} else {
		log.Fatal(http.ListenAndServe(":"+strconv.Itoa(config.Port), r))
	}
}

// RootHandler handles the root route.
// This includes the homepage and the
// file system.
func RootHandler(t *template.Template) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		switch url := r.URL.Path; url {
		case "/":
			if config.CSRF {
				w.Header().Set("X-CSRF-Token", csrf.Token(r))
				err := t.ExecuteTemplate(w, "index.html", map[string]interface{}{
					csrf.TemplateTag: csrf.TemplateField(r),
				})
				if err != nil {
					w.WriteHeader(http.StatusInternalServerError)
				}
			} else {
				err := t.ExecuteTemplate(w, "index.html", map[string]interface{}{
					csrf.TemplateTag: "",
				})
				if err != nil {
					w.WriteHeader(http.StatusInternalServerError)
				}
			}
		default:
			if _, err := os.Stat(config.PublicDirectory + url); err != nil {
				http.ServeFile(w, r, config.TemplateDirectory+"404.html")
			} else {
				http.ServeFile(w, r, config.PublicDirectory+url)
			}
		}

	}
}

// Handles the ability to view your image.
// It checks if the file exists, and returns
// an appropriate response.
//
// If the image exists, it serves a template
// which is defined in
// TemplateDirectory/view.html.
func ViewHandler(t *template.Template) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		vars := mux.Vars(r)
		id := vars["id"]
		ext := util.GetFileExtFromDir(id, config.ImageDirectory)
		if ext != "" {
			err := t.ExecuteTemplate(w, "view.html", ViewData{
				Id:       id,
				ImageUrl: config.ImageUrl,
				Ext:      ext,
			})
			if err != nil {
				w.WriteHeader(http.StatusInternalServerError)
				log.Fatal(err)
				return
			}
		} else {
			w.Header().Add("Content-Type", "text/html; charset=utf-8")
			w.WriteHeader(http.StatusNotFound)
			http.ServeFile(w, r, config.TemplateDirectory+"404.html")
		}
	}
}

// Handles the upload route.
// It checks the file, and uploads the
// image to the ImageDirectory defined
// in the config.json
func UploadHandler(w http.ResponseWriter, r *http.Request) {
	r.ParseMultipartForm(30000000)
	file, handler, err := r.FormFile("file")
	if err != nil {
		log.Fatal(err)
		return
	}
	defer file.Close()

	if CheckFileType(handler.Header) == false {
		http.Redirect(w, r, "/", http.StatusSeeOther)
		return
	}

	name := GenerateName(config.ImageNameLength)
	f, err := os.OpenFile(config.ImageDirectory+name+util.GetFileExt(handler.Header["Content-Disposition"][0]), os.O_WRONLY|os.O_CREATE, 0644)
	if err != nil {
		log.Fatal(err)
		return
	}

	io.Copy(f, file)
	fStat, err := f.Stat()
	if err != nil {
		log.Fatal(err)
	}
	size := fStat.Size()
	if size > config.MaxFileSize {
		f.Close()
		err = os.RemoveAll(config.ImageDirectory + name + util.GetFileExt(handler.Header["Content-Disposition"][0]))
		if err != nil {
			log.Fatal(err)
		}
		http.Redirect(w, r, "/", http.StatusSeeOther)
	} else {
		http.Redirect(w, r, "/"+name+"/", http.StatusSeeOther)
		f.Close()
	}
}

// CheckFileType checks if the uploaded
// file's extension is allowed.
// It accepts a textproto.MIMEHeader
// which is recieved from the http.Request
// FormFile function, as the handler.Header
func CheckFileType(f textproto.MIMEHeader) bool {
	ext := util.GetFileExt(f["Content-Disposition"][0])

	if !util.Contains(config.AllowedMimeTypes, f["Content-Type"][0]) || !util.Contains(config.AllowedExtensions, ext) {
		return false
	}

	return true
}

// GenerateName generates a name with
// a specified length, and checks if
// the name already exists, using the
// util functions for this.
func GenerateName(n int) string {
	name := util.GenerateName(n)

	for util.CheckExists(name, config.ImageDirectory) {
		name = util.GenerateName(n)
	}

	return name
}
<commit_msg>Minor bug fix<commit_after>package main

import (
	"encoding/json"
	"html/template"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"net/textproto"
	"os"
	"strconv"

	"github.com/Omar-H/goimage/util"
	"github.com/gorilla/csrf"
	"github.com/gorilla/mux"
)

// Data parsed to the ViewHandler's template
type ViewData struct {
	Id       string
	ImageUrl string
	Ext      string
}

// Parsed JSON config
type Config struct {
	Port              int      `json:"port"`
	Secure            bool     `json:"secure"`
	AuthKey           string   `json:"32-byte-auth-key"`
	AllowedMimeTypes  []string `json:"allowed-mime-types"`
	AllowedExtensions []string `json:"allowed-extensions"`
	ImageNameLength   int      `json:"image-name-length"`
	MaxFileSize       int64    `json:"max-file-size"`
	ImageDirectory    string   `json:"image-directory"`
	TemplateDirectory string   `json:"template-directory"`
	PublicDirectory   string   `json:"public-directory"`
	ImageUrl          string   `json:"image-url"`
	CSRF              bool     `json:"csrf"`
}

var config Config

func main() {
	jsonFiles, err := ioutil.ReadFile("./config.json")
	if err != nil {
		log.Fatal(err)
		return
	}
	json.Unmarshal(jsonFiles, &config)

	CSRF := csrf.Protect(
		[]byte(config.AuthKey),
		csrf.RequestHeader("X-CSRF-Token"),
		csrf.FieldName("_csrf"),
		csrf.Secure(config.Secure),
	)
	r := mux.NewRouter()
	err = os.MkdirAll(config.TemplateDirectory, 644)
	if err != nil {
		log.Fatal("Unable to create Template Directory")
	}
	err = os.MkdirAll(config.PublicDirectory, 644)
	if err != nil {
		log.Fatal("Unable to create Public Directory")
	}
	err = os.MkdirAll(config.ImageDirectory, 644)
	if err != nil {
		log.Fatal("Unable to create Image Directory")
	}

	templates := template.Must(template.ParseGlob(config.TemplateDirectory + "*.html"))

	r.HandleFunc("/{id}/", ViewHandler(templates)).Methods("GET")
	r.HandleFunc("/upload/", UploadHandler).Methods("POST")
	r.PathPrefix("/").HandlerFunc(RootHandler(templates)).Methods("GET")

	log.Print("Listening on port " + strconv.Itoa(config.Port))
	if config.CSRF {
		log.Fatal(http.ListenAndServe(":"+strconv.Itoa(config.Port), CSRF(r)))
	} else {
		log.Fatal(http.ListenAndServe(":"+strconv.Itoa(config.Port), r))
	}
}

// RootHandler handles the root route.
// This includes the homepage and the
// file system.
func RootHandler(t *template.Template) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		switch url := r.URL.Path; url {
		case "/":
			if config.CSRF {
				w.Header().Set("X-CSRF-Token", csrf.Token(r))
				err := t.ExecuteTemplate(w, "index.html", map[string]interface{}{
					csrf.TemplateTag: csrf.TemplateField(r),
				})
				if err != nil {
					w.WriteHeader(http.StatusInternalServerError)
				}
			} else {
				err := t.ExecuteTemplate(w, "index.html", map[string]interface{}{
					csrf.TemplateTag: "",
				})
				if err != nil {
					w.WriteHeader(http.StatusInternalServerError)
				}
			}
		default:
			if _, err := os.Stat(config.PublicDirectory + url); err != nil {
				w.Header().Add("Content-Type", "text/html; charset=utf-8")
				w.WriteHeader(http.StatusNotFound)
				http.ServeFile(w, r, config.TemplateDirectory+"404.html")
			} else {
				http.ServeFile(w, r, config.PublicDirectory+url)
			}
		}

	}
}

// Handles the ability to view your image.
// It checks if the file exists, and returns
// an appropriate response.
//
// If the image exists, it serves a template
// which is defined in
// TemplateDirectory/view.html.
func ViewHandler(t *template.Template) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		vars := mux.Vars(r)
		id := vars["id"]
		ext := util.GetFileExtFromDir(id, config.ImageDirectory)
		if ext != "" {
			err := t.ExecuteTemplate(w, "view.html", ViewData{
				Id:       id,
				ImageUrl: config.ImageUrl,
				Ext:      ext,
			})
			if err != nil {
				w.WriteHeader(http.StatusInternalServerError)
				log.Fatal(err)
				return
			}
		} else {
			w.Header().Add("Content-Type", "text/html; charset=utf-8")
			w.WriteHeader(http.StatusNotFound)
			http.ServeFile(w, r, config.TemplateDirectory+"404.html")
		}
	}
}

// Handles the upload route.
// It checks the file, and uploads the
// image to the ImageDirectory defined
// in the config.json
func UploadHandler(w http.ResponseWriter, r *http.Request) {
	r.ParseMultipartForm(30000000)
	file, handler, err := r.FormFile("file")
	if err != nil {
		log.Fatal(err)
		return
	}
	defer file.Close()

	if CheckFileType(handler.Header) == false {
		http.Redirect(w, r, "/", http.StatusSeeOther)
		return
	}

	name := GenerateName(config.ImageNameLength)
	f, err := os.OpenFile(config.ImageDirectory+name+util.GetFileExt(handler.Header["Content-Disposition"][0]), os.O_WRONLY|os.O_CREATE, 0644)
	if err != nil {
		log.Fatal(err)
		return
	}

	io.Copy(f, file)
	fStat, err := f.Stat()
	if err != nil {
		log.Fatal(err)
	}
	size := fStat.Size()
	if size > config.MaxFileSize {
		f.Close()
		err = os.RemoveAll(config.ImageDirectory + name + util.GetFileExt(handler.Header["Content-Disposition"][0]))
		if err != nil {
			log.Fatal(err)
		}
		http.Redirect(w, r, "/", http.StatusSeeOther)
	} else {
		http.Redirect(w, r, "/"+name+"/", http.StatusSeeOther)
		f.Close()
	}
}

// CheckFileType checks if the uploaded
// file's extension is allowed.
// It accepts a textproto.MIMEHeader
// which is recieved from the http.Request
// FormFile function, as the handler.Header
func CheckFileType(f textproto.MIMEHeader) bool {
	ext := util.GetFileExt(f["Content-Disposition"][0])

	if !util.Contains(config.AllowedMimeTypes, f["Content-Type"][0]) || !util.Contains(config.AllowedExtensions, ext) {
		return false
	}

	return true
}

// GenerateName generates a name with
// a specified length, and checks if
// the name already exists, using the
// util functions for this.
func GenerateName(n int) string {
	name := util.GenerateName(n)

	for util.CheckExists(name, config.ImageDirectory) {
		name = util.GenerateName(n)
	}

	return name
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"crypto/tls"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"mime"
	"net/http"
	"net/http/httptrace"
	"net/url"
	"os"
	"path"
	"sort"
	"strconv"
	"strings"
	"time"

	"net"

	"github.com/fatih/color"
)

const (
	HTTPSTemplate = `` +
		`  DNS Lookup   TCP Connection   TLS Handshake   Server Processing   Content Transfer` + "\n" +
		`[%s  |     %s  |    %s  |        %s  |       %s  ]` + "\n" +
		`            |                |               |                   |                  |` + "\n" +
		`   namelookup:%s      |               |                   |                  |` + "\n" +
		`                       connect:%s     |                   |                  |` + "\n" +
		`                                   pretransfer:%s         |                  |` + "\n" +
		`                                                     starttransfer:%s        |` + "\n" +
		`                                                                                total:%s` + "\n"

	HTTPTemplate = `` +
		`   DNS Lookup   TCP Connection   Server Processing   Content Transfer` + "\n" +
		`[ %s  |     %s  |        %s  |       %s  ]` + "\n" +
		`             |                |                   |                  |` + "\n" +
		`    namelookup:%s      |                   |                  |` + "\n" +
		`                        connect:%s         |                  |` + "\n" +
		`                                      starttransfer:%s        |` + "\n" +
		`                                                                 total:%s` + "\n"
)

var (
	grayscale = func(code int) func(string) string {
		if color.NoColor {
			return func(s string) string { return s }
		}
		return func(s string) string {
			return fmt.Sprintf("\x1b[;38;5;%dm%s\x1b[0m", code+232, s)
		}
	}

	// Command line flags.
	httpMethod      string
	postBody        string
	followRedirects bool
	onlyHeader      bool
	insecure        bool
	httpHeaders     headers
	saveOutput      bool
	outputFile      string

	// number of redirects followed
	redirectsFollowed int

	usage = fmt.Sprintf("usage: %s URL", os.Args[0])
)

const maxRedirects = 10

func init() {
	flag.StringVar(&httpMethod, "X", "GET", "HTTP method to use")
	flag.StringVar(&postBody, "d", "", "the body of a POST or PUT request")
	flag.BoolVar(&followRedirects, "L", false, "follow 30x redirects")
	flag.BoolVar(&onlyHeader, "I", false, "don't read body of request")
	flag.BoolVar(&insecure, "k", false, "allow insecure SSL connections")
	flag.Var(&httpHeaders, "H", "HTTP Header(s) to set. Can be used multiple times. -H 'Accept:...' -H 'Range:....'")
	flag.BoolVar(&saveOutput, "O", false, "Save body as remote filename")
	flag.StringVar(&outputFile, "o", "", "output file for body")

	flag.Usage = func() {
		os.Stderr.WriteString(usage + "\n")
		flag.PrintDefaults()
		os.Exit(2)
	}
}

func printf(format string, a ...interface{}) (n int, err error) {
	if color.Output == os.Stdout {
		return fmt.Printf(format, a...)
	}
	return fmt.Fprintf(color.Output, format, a...)
}

func main() {
	flag.Parse()

	args := flag.Args()
	if len(args) != 1 {
		flag.Usage()
	}

	if (httpMethod == "POST" || httpMethod == "PUT") && postBody == "" {
		log.Fatal("must supply post body using -d when POST or PUT is used")
	}

	url := parseURL(args[0])

	visit(url)
}

func parseURL(uri string) *url.URL {
	if !strings.Contains(uri, "://") && !strings.HasPrefix(uri, "//") {
		uri = "//" + uri
	}

	url, err := url.Parse(uri)
	if err != nil {
		log.Fatalf("could not parse url %q: %v", uri, err)
	}

	if url.Scheme == "" {
		url.Scheme = "http"
		if !strings.HasSuffix(url.Host, ":80") {
			url.Scheme += "s"
		}
	}
	return url
}

func headerKeyValue(h string) (string, string) {
	i := strings.Index(h, ":")
	if i == -1 {
		log.Fatalf("Header '%s' has invalid format, missing ':'", h)
	}
	return strings.TrimRight(h[:i], " "), strings.TrimLeft(h[i:], " :")
}

func getHostPort(url *url.URL) (string, string, string) {
	scheme := url.Scheme
	URLHost := url.Host

	// No hostname, just a port
	if strings.HasPrefix(URLHost, ":") {
		URLHost = "localhost" + URLHost
	}

	host, port, err := net.SplitHostPort(URLHost)
	if err != nil {
		host = URLHost
	}

	switch scheme {
	case "https":
		if port == "" {
			port = "443"
		}
	case "http":
		if port == "" {
			port = "80"
		}
	default:
		log.Fatalf("unsupported url scheme %q", scheme)
	}

	return scheme, host, port
}

// visit visits a url and times the interaction.
// If the response is a 30x, visit follows the redirect.
func visit(url *url.URL) {
	scheme, host, _ := getHostPort(url)

	host, _, err := net.SplitHostPort(url.Host)
	if err != nil {
		host = url.Host
	}

	var t0, t1, t2, t3, t4 time.Time

	trace := &httptrace.ClientTrace{
		DNSStart: func(i httptrace.DNSStartInfo) { t0 = time.Now() },
		DNSDone:  func(i httptrace.DNSDoneInfo) { t1 = time.Now() },
		ConnectDone: func(net, addr string, err error) {
			if err != nil {
				log.Fatalf("unable to connect to host %v %v", addr, err)
			}
			t2 = time.Now()

			printf("\n%s%s\n", color.GreenString("Connected to "), color.CyanString("%s", addr))
		},
		WroteRequest:         func(i httptrace.WroteRequestInfo) { t3 = time.Now() },
		GotFirstResponseByte: func() { t4 = time.Now() },
	}

	if onlyHeader {
		httpMethod = "HEAD"
	}

	req, err := http.NewRequest(httpMethod, url.String(), createBody(postBody))
	if err != nil {
		log.Fatalf("unable to create request: %v", err)
	}
	for _, h := range httpHeaders {
		k, v := headerKeyValue(h)
		if strings.EqualFold(k, "host") {
			req.Host = v
			continue
		}
		req.Header.Add(k, v)
	}

	req = req.WithContext(httptrace.WithClientTrace(context.Background(), trace))

	tr := &http.Transport{}
	if scheme == "https" {
		tr.TLSClientConfig = &tls.Config{
			ServerName:         host,
			InsecureSkipVerify: insecure,
		}
	}

	client := &http.Client{
		Transport: tr,
		CheckRedirect: func(req *http.Request, via []*http.Request) error {
			if !followRedirects {
				return http.ErrUseLastResponse
			}
			if len(via) >= maxRedirects {
				return fmt.Errorf("stopped after %d redirects", maxRedirects)
			}
			return nil
		},
	}

	resp, err := client.Do(req)

	if err != nil {
		log.Fatalf("failed to read response: %v", err)
	}

	bodyMsg := readResponseBody(req, resp)

	t5 := time.Now() // after read body

	// print status line and headers
	printf("\n%s%s%s\n", color.GreenString("HTTP"), grayscale(14)("/"), color.CyanString("%d.%d %s", resp.ProtoMajor, resp.ProtoMinor, resp.Status))

	names := make([]string, 0, len(resp.Header))
	for k := range resp.Header {
		names = append(names, k)
	}
	sort.Sort(headers(names))
	for _, k := range names {
		printf("%s %s\n", grayscale(14)(k+":"), color.CyanString("%s", strings.Join(resp.Header[k], ",")))
	}

	if bodyMsg != "" {
		printf("\n%s\n", bodyMsg)
	}

	fmta := func(d time.Duration) string {
		return color.CyanString("%7dms", int(d/time.Millisecond))
	}

	fmtb := func(d time.Duration) string {
		return color.CyanString("%-9s", strconv.Itoa(int(d/time.Millisecond))+"ms")
	}

	colorize := func(s string) string {
		v := strings.Split(s, "\n")
		v[0] = grayscale(16)(v[0])
		return strings.Join(v, "\n")
	}

	fmt.Println()

	switch scheme {
	case "https":
		printf(colorize(HTTPSTemplate),
			fmta(t1.Sub(t0)), // dns lookup
			fmta(t2.Sub(t1)), // tcp connection
			fmta(t3.Sub(t2)), // tls handshake
			fmta(t4.Sub(t3)), // server processing
			fmta(t5.Sub(t4)), // content transfer
			fmtb(t1.Sub(t0)), // namelookup
			fmtb(t2.Sub(t0)), // connect
			fmtb(t3.Sub(t0)), // pretransfer
			fmtb(t4.Sub(t0)), // starttransfer
			fmtb(t5.Sub(t0)), // total
		)
	case "http":
		printf(colorize(HTTPTemplate),
			fmta(t1.Sub(t0)), // dns lookup
			fmta(t3.Sub(t1)), // tcp connection
			fmta(t4.Sub(t3)), // server processing
			fmta(t5.Sub(t4)), // content transfer
			fmtb(t1.Sub(t0)), // namelookup
			fmtb(t3.Sub(t0)), // connect
			fmtb(t4.Sub(t0)), // starttransfer
			fmtb(t5.Sub(t0)), // total
		)
	}

	if followRedirects && isRedirect(resp) {
		loc, err := resp.Location()
		if err != nil {
			if err == http.ErrNoLocation {
				// 30x but no Location to follow, give up.
				return
			}
			log.Fatalf("unable to follow redirect: %v", err)
		}

		redirectsFollowed++
		if redirectsFollowed > maxRedirects {
			log.Fatalf("maximum number of redirects (%d) followed\n", maxRedirects)
		}

		visit(loc)
	}
}

func isRedirect(resp *http.Response) bool {
	return resp.StatusCode > 299 && resp.StatusCode < 400
}

func createBody(body string) io.Reader {
	if strings.HasPrefix(body, "@") {
		filename := body[1:]
		f, err := os.Open(filename)
		if err != nil {
			log.Fatalf("failed to open data file %s: %v", filename, err)
		}
		return f
	}
	return strings.NewReader(body)
}

// getFilenameFromHeaders tries to automatically determine the output filename,
// when saving to disk, based on the Content-Disposition header.
// If the header is not present, or it does not contain enough information to
// determine which filename to use, this function returns "".
func getFilenameFromHeaders(headers http.Header) string {
	// if the Content-Disposition header is set parse it
	if hdr := headers.Get("Content-Disposition"); hdr != "" {
		// pull the media type, and subsequent params, from
		// the body of the header field
		mt, params, err := mime.ParseMediaType(hdr)

		// if there was no error and the media type is attachment
		if err == nil && mt == "attachment" {
			if filename := params["filename"]; filename != "" {
				return filename
			}
		}
	}

	// return an empty string if we were unable to determine the filename
	return ""
}

// readResponseBody consumes the body of the response.
// readResponseBody returns an informational message about the
// disposition of the response body's contents.
func readResponseBody(req *http.Request, resp *http.Response) string {
	if isRedirect(resp) || req.Method == http.MethodHead {
		return ""
	}

	w := ioutil.Discard
	msg := color.CyanString("Body discarded")

	if saveOutput == true || outputFile != "" {
		filename := outputFile

		if saveOutput == true {
			// try to get the filename from the Content-Disposition header
			// otherwise fall back to the RequestURI
			if filename = getFilenameFromHeaders(resp.Header); filename == "" {
				filename = path.Base(req.URL.RequestURI())
			}

			if filename == "/" {
				log.Fatalf("No remote filename; specify output filename with -o to save response body")
			}
		}

		f, err := os.Create(filename)
		if err != nil {
			log.Fatalf("unable to create file %s", outputFile)
		}
		defer f.Close()
		w = f
		msg = color.CyanString("Body read")
	}

	if _, err := io.Copy(w, resp.Body); err != nil {
		log.Fatalf("failed to read response body: %v", err)
	}

	return msg
}

type headers []string

func (h headers) String() string {
	var o []string
	for _, v := range h {
		o = append(o, "-H "+v)
	}
	return strings.Join(o, " ")
}

func (h *headers) Set(v string) error {
	*h = append(*h, v)
	return nil
}

func (h headers) Len() int      { return len(h) }
func (h headers) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
func (h headers) Less(i, j int) bool {
	a, b := h[i], h[j]

	// server always sorts at the top
	if a == "Server" {
		return true
	}
	if b == "Server" {
		return false
	}

	endtoend := func(n string) bool {
		// https://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.5.1
		switch n {
		case "Connection",
			"Keep-Alive",
			"Proxy-Authenticate",
			"Proxy-Authorization",
			"TE",
			"Trailers",
			"Transfer-Encoding",
			"Upgrade":
			return false
		default:
			return true
		}
	}

	x, y := endtoend(a), endtoend(b)
	if x == y {
		// both are of the same class
		return a < b
	}
	return x
}
<commit_msg>Remove color work-around (#81)<commit_after>package main

import (
	"context"
	"crypto/tls"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"mime"
	"net/http"
	"net/http/httptrace"
	"net/url"
	"os"
	"path"
	"sort"
	"strconv"
	"strings"
	"time"

	"net"

	"github.com/fatih/color"
)

const (
	HTTPSTemplate = `` +
		`  DNS Lookup   TCP Connection   TLS Handshake   Server Processing   Content Transfer` + "\n" +
		`[%s  |     %s  |    %s  |        %s  |       %s  ]` + "\n" +
		`            |                |               |                   |                  |` + "\n" +
		`   namelookup:%s      |               |                   |                  |` + "\n" +
		`                       connect:%s     |                   |                  |` + "\n" +
		`                                   pretransfer:%s         |                  |` + "\n" +
		`                                                     starttransfer:%s        |` + "\n" +
		`                                                                                total:%s` + "\n"

	HTTPTemplate = `` +
		`   DNS Lookup   TCP Connection   Server Processing   Content Transfer` + "\n" +
		`[ %s  |     %s  |        %s  |       %s  ]` + "\n" +
		`             |                |                   |                  |` + "\n" +
		`    namelookup:%s      |                   |                  |` + "\n" +
		`                        connect:%s         |                  |` + "\n" +
		`                                      starttransfer:%s        |` + "\n" +
		`                                                                 total:%s` + "\n"
)

var (
	grayscale = func(code int) func(string) string {
		if color.NoColor {
			return func(s string) string { return s }
		}
		return func(s string) string {
			return fmt.Sprintf("\x1b[;38;5;%dm%s\x1b[0m", code+232, s)
		}
	}

	// Command line flags.
	httpMethod      string
	postBody        string
	followRedirects bool
	onlyHeader      bool
	insecure        bool
	httpHeaders     headers
	saveOutput      bool
	outputFile      string

	// number of redirects followed
	redirectsFollowed int

	usage = fmt.Sprintf("usage: %s URL", os.Args[0])
)

const maxRedirects = 10

func init() {
	flag.StringVar(&httpMethod, "X", "GET", "HTTP method to use")
	flag.StringVar(&postBody, "d", "", "the body of a POST or PUT request")
	flag.BoolVar(&followRedirects, "L", false, "follow 30x redirects")
	flag.BoolVar(&onlyHeader, "I", false, "don't read body of request")
	flag.BoolVar(&insecure, "k", false, "allow insecure SSL connections")
	flag.Var(&httpHeaders, "H", "HTTP Header(s) to set. Can be used multiple times. -H 'Accept:...' -H 'Range:....'")
	flag.BoolVar(&saveOutput, "O", false, "Save body as remote filename")
	flag.StringVar(&outputFile, "o", "", "output file for body")

	flag.Usage = func() {
		os.Stderr.WriteString(usage + "\n")
		flag.PrintDefaults()
		os.Exit(2)
	}
}

func printf(format string, a ...interface{}) (n int, err error) {
	if color.Output == os.Stdout {
		return fmt.Printf(format, a...)
	}
	return fmt.Fprintf(color.Output, format, a...)
}

func main() {
	flag.Parse()

	args := flag.Args()
	if len(args) != 1 {
		flag.Usage()
	}

	if (httpMethod == "POST" || httpMethod == "PUT") && postBody == "" {
		log.Fatal("must supply post body using -d when POST or PUT is used")
	}

	url := parseURL(args[0])

	visit(url)
}

func parseURL(uri string) *url.URL {
	if !strings.Contains(uri, "://") && !strings.HasPrefix(uri, "//") {
		uri = "//" + uri
	}

	url, err := url.Parse(uri)
	if err != nil {
		log.Fatalf("could not parse url %q: %v", uri, err)
	}

	if url.Scheme == "" {
		url.Scheme = "http"
		if !strings.HasSuffix(url.Host, ":80") {
			url.Scheme += "s"
		}
	}
	return url
}

func headerKeyValue(h string) (string, string) {
	i := strings.Index(h, ":")
	if i == -1 {
		log.Fatalf("Header '%s' has invalid format, missing ':'", h)
	}
	return strings.TrimRight(h[:i], " "), strings.TrimLeft(h[i:], " :")
}

func getHostPort(url *url.URL) (string, string, string) {
	scheme := url.Scheme
	URLHost := url.Host

	// No hostname, just a port
	if strings.HasPrefix(URLHost, ":") {
		URLHost = "localhost" + URLHost
	}

	host, port, err := net.SplitHostPort(URLHost)
	if err != nil {
		host = URLHost
	}

	switch scheme {
	case "https":
		if port == "" {
			port = "443"
		}
	case "http":
		if port == "" {
			port = "80"
		}
	default:
		log.Fatalf("unsupported url scheme %q", scheme)
	}

	return scheme, host, port
}

// visit visits a url and times the interaction.
// If the response is a 30x, visit follows the redirect.
func visit(url *url.URL) {
	scheme, host, _ := getHostPort(url)

	host, _, err := net.SplitHostPort(url.Host)
	if err != nil {
		host = url.Host
	}

	var t0, t1, t2, t3, t4 time.Time

	trace := &httptrace.ClientTrace{
		DNSStart: func(i httptrace.DNSStartInfo) { t0 = time.Now() },
		DNSDone:  func(i httptrace.DNSDoneInfo) { t1 = time.Now() },
		ConnectDone: func(net, addr string, err error) {
			if err != nil {
				log.Fatalf("unable to connect to host %v %v", addr, err)
			}
			t2 = time.Now()

			printf("\n%s%s\n", color.GreenString("Connected to "), color.CyanString(addr))
		},
		WroteRequest:         func(i httptrace.WroteRequestInfo) { t3 = time.Now() },
		GotFirstResponseByte: func() { t4 = time.Now() },
	}

	if onlyHeader {
		httpMethod = "HEAD"
	}

	req, err := http.NewRequest(httpMethod, url.String(), createBody(postBody))
	if err != nil {
		log.Fatalf("unable to create request: %v", err)
	}
	for _, h := range httpHeaders {
		k, v := headerKeyValue(h)
		if strings.EqualFold(k, "host") {
			req.Host = v
			continue
		}
		req.Header.Add(k, v)
	}

	req = req.WithContext(httptrace.WithClientTrace(context.Background(), trace))

	tr := &http.Transport{}
	if scheme == "https" {
		tr.TLSClientConfig = &tls.Config{
			ServerName:         host,
			InsecureSkipVerify: insecure,
		}
	}

	client := &http.Client{
		Transport: tr,
		CheckRedirect: func(req *http.Request, via []*http.Request) error {
			if !followRedirects {
				return http.ErrUseLastResponse
			}
			if len(via) >= maxRedirects {
				return fmt.Errorf("stopped after %d redirects", maxRedirects)
			}
			return nil
		},
	}

	resp, err := client.Do(req)

	if err != nil {
		log.Fatalf("failed to read response: %v", err)
	}

	bodyMsg := readResponseBody(req, resp)

	t5 := time.Now() // after read body

	// print status line and headers
	printf("\n%s%s%s\n", color.GreenString("HTTP"), grayscale(14)("/"), color.CyanString("%d.%d %s", resp.ProtoMajor, resp.ProtoMinor, resp.Status))

	names := make([]string, 0, len(resp.Header))
	for k := range resp.Header {
		names = append(names, k)
	}
	sort.Sort(headers(names))
	for _, k := range names {
		printf("%s %s\n", grayscale(14)(k+":"), color.CyanString(strings.Join(resp.Header[k], ",")))
	}

	if bodyMsg != "" {
		printf("\n%s\n", bodyMsg)
	}

	fmta := func(d time.Duration) string {
		return color.CyanString("%7dms", int(d/time.Millisecond))
	}

	fmtb := func(d time.Duration) string {
		return color.CyanString("%-9s", strconv.Itoa(int(d/time.Millisecond))+"ms")
	}

	colorize := func(s string) string {
		v := strings.Split(s, "\n")
		v[0] = grayscale(16)(v[0])
		return strings.Join(v, "\n")
	}

	fmt.Println()

	switch scheme {
	case "https":
		printf(colorize(HTTPSTemplate),
			fmta(t1.Sub(t0)), // dns lookup
			fmta(t2.Sub(t1)), // tcp connection
			fmta(t3.Sub(t2)), // tls handshake
			fmta(t4.Sub(t3)), // server processing
			fmta(t5.Sub(t4)), // content transfer
			fmtb(t1.Sub(t0)), // namelookup
			fmtb(t2.Sub(t0)), // connect
			fmtb(t3.Sub(t0)), // pretransfer
			fmtb(t4.Sub(t0)), // starttransfer
			fmtb(t5.Sub(t0)), // total
		)
	case "http":
		printf(colorize(HTTPTemplate),
			fmta(t1.Sub(t0)), // dns lookup
			fmta(t3.Sub(t1)), // tcp connection
			fmta(t4.Sub(t3)), // server processing
			fmta(t5.Sub(t4)), // content transfer
			fmtb(t1.Sub(t0)), // namelookup
			fmtb(t3.Sub(t0)), // connect
			fmtb(t4.Sub(t0)), // starttransfer
			fmtb(t5.Sub(t0)), // total
		)
	}

	if followRedirects && isRedirect(resp) {
		loc, err := resp.Location()
		if err != nil {
			if err == http.ErrNoLocation {
				// 30x but no Location to follow, give up.
				return
			}
			log.Fatalf("unable to follow redirect: %v", err)
		}

		redirectsFollowed++
		if redirectsFollowed > maxRedirects {
			log.Fatalf("maximum number of redirects (%d) followed\n", maxRedirects)
		}

		visit(loc)
	}
}

func isRedirect(resp *http.Response) bool {
	return resp.StatusCode > 299 && resp.StatusCode < 400
}

func createBody(body string) io.Reader {
	if strings.HasPrefix(body, "@") {
		filename := body[1:]
		f, err := os.Open(filename)
		if err != nil {
			log.Fatalf("failed to open data file %s: %v", filename, err)
		}
		return f
	}
	return strings.NewReader(body)
}

// getFilenameFromHeaders tries to automatically determine the output filename,
// when saving to disk, based on the Content-Disposition header.
// If the header is not present, or it does not contain enough information to
// determine which filename to use, this function returns "".
func getFilenameFromHeaders(headers http.Header) string {
	// if the Content-Disposition header is set parse it
	if hdr := headers.Get("Content-Disposition"); hdr != "" {
		// pull the media type, and subsequent params, from
		// the body of the header field
		mt, params, err := mime.ParseMediaType(hdr)

		// if there was no error and the media type is attachment
		if err == nil && mt == "attachment" {
			if filename := params["filename"]; filename != "" {
				return filename
			}
		}
	}

	// return an empty string if we were unable to determine the filename
	return ""
}

// readResponseBody consumes the body of the response.
// readResponseBody returns an informational message about the
// disposition of the response body's contents.
func readResponseBody(req *http.Request, resp *http.Response) string {
	if isRedirect(resp) || req.Method == http.MethodHead {
		return ""
	}

	w := ioutil.Discard
	msg := color.CyanString("Body discarded")

	if saveOutput == true || outputFile != "" {
		filename := outputFile

		if saveOutput == true {
			// try to get the filename from the Content-Disposition header
			// otherwise fall back to the RequestURI
			if filename = getFilenameFromHeaders(resp.Header); filename == "" {
				filename = path.Base(req.URL.RequestURI())
			}

			if filename == "/" {
				log.Fatalf("No remote filename; specify output filename with -o to save response body")
			}
		}

		f, err := os.Create(filename)
		if err != nil {
			log.Fatalf("unable to create file %s", outputFile)
		}
		defer f.Close()
		w = f
		msg = color.CyanString("Body read")
	}

	if _, err := io.Copy(w, resp.Body); err != nil {
		log.Fatalf("failed to read response body: %v", err)
	}

	return msg
}

type headers []string

func (h headers) String() string {
	var o []string
	for _, v := range h {
		o = append(o, "-H "+v)
	}
	return strings.Join(o, " ")
}

func (h *headers) Set(v string) error {
	*h = append(*h, v)
	return nil
}

func (h headers) Len() int      { return len(h) }
func (h headers) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
func (h headers) Less(i, j int) bool {
	a, b := h[i], h[j]

	// server always sorts at the top
	if a == "Server" {
		return true
	}
	if b == "Server" {
		return false
	}

	endtoend := func(n string) bool {
		// https://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.5.1
		switch n {
		case "Connection",
			"Keep-Alive",
			"Proxy-Authenticate",
			"Proxy-Authorization",
			"TE",
			"Trailers",
			"Transfer-Encoding",
			"Upgrade":
			return false
		default:
			return true
		}
	}

	x, y := endtoend(a), endtoend(b)
	if x == y {
		// both are of the same class
		return a < b
	}
	return x
}
<|endoftext|>