<commit_before>package main

import (
	"github.com/jasonlvhit/gocron"
	"github.com/jinzhu/gorm"
	_ "github.com/jinzhu/gorm/dialects/sqlite"
	"gopkg.in/telegram-bot-api.v4"
	"log"
)

const (
	TIMEOUT       = 60
	DATABASE      = "sqlite3"
	DATABASE_NAME = "db.sqlite3"
)

var (
	bot *tgbotapi.BotAPI
	gdb *gorm.DB
)

// You must create bot_token.go file, which include TOKEN variable in global package scope
func init() {
	var err error

	gdb, err = gorm.Open(DATABASE, DATABASE_NAME)
	if err != nil {
		panic(err)
	}
	gdb.LogMode(true)

	gdb.AutoMigrate(
		&Users{},
		&Groups{},
		&Available{},
	)

	go startSchedule()

	bot, err = tgbotapi.NewBotAPI(TOKEN)

	if err != nil {
		err.Error()
	}

	bot.Debug = true
	log.Printf("Authorized on account %s", bot.Self.UserName)

}

func main() {
	defer gdb.Close()

	u := tgbotapi.NewUpdate(0)
	u.Timeout = TIMEOUT

	updates, err := bot.GetUpdatesChan(u)
	if err != nil {
		err.Error()
	}

	for update := range updates {
		msg := update.Message
		if msg == nil {
			continue
		}
		if msg.IsCommand() {
			command := msg.Command()
			createGroupRecord(msg)
			createAvailableRecord(msg)
			checkIfUsernameChanged(msg)
			switch command {
			case "regpi":
				regpi(msg, update)
			case "showpid":
				showpid(msg)
			case "pidor":
				startQuiz(msg)
			case "pidorstat":
				pidorStat(msg)
			}
		}
	}

}
<commit_msg>fixed import file<commit_after>package main

import (
	"github.com/jinzhu/gorm"
	_ "github.com/jinzhu/gorm/dialects/sqlite"
	"gopkg.in/telegram-bot-api.v4"
	"log"
)

const (
	TIMEOUT       = 60
	DATABASE      = "sqlite3"
	DATABASE_NAME = "db.sqlite3"
)

var (
	bot *tgbotapi.BotAPI
	gdb *gorm.DB
)

// You must create bot_token.go file, which include TOKEN variable in global package scope
func init() {
	var err error

	gdb, err = gorm.Open(DATABASE, DATABASE_NAME)
	if err != nil {
		panic(err)
	}
	gdb.LogMode(true)

	gdb.AutoMigrate(
		&Users{},
		&Groups{},
		&Available{},
	)

	go startSchedule()

	bot, err = tgbotapi.NewBotAPI(TOKEN)

	if err != nil {
		err.Error()
	}

	bot.Debug = true
	log.Printf("Authorized on account %s", bot.Self.UserName)

}

func main() {
	defer gdb.Close()

	u := tgbotapi.NewUpdate(0)
	u.Timeout = TIMEOUT

	updates, err := bot.GetUpdatesChan(u)
	if err != nil {
		err.Error()
	}

	for update := range updates {
		msg := update.Message
		if msg == nil {
			continue
		}
		if msg.IsCommand() {
			command := msg.Command()
			createGroupRecord(msg)
			createAvailableRecord(msg)
			checkIfUsernameChanged(msg)
			switch command {
			case "regpi":
				regpi(msg, update)
			case "showpid":
				showpid(msg)
			case "pidor":
				startQuiz(msg)
			case "pidorstat":
				pidorStat(msg)
			}
		}
	}

}
<|endoftext|>


<commit_before>package main

import (
    "fmt"
    "net/http"
    "html/template"
)

var templates = template.Must(template.ParseGlob("templates/*"))

func handler(w http.ResponseWriter, r *http.Request) {
    title := r.URL.Path[1:]
    err := templates.ExecuteTemplate(w, "index", title)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
}

func main() {
    http.HandleFunc("/", handler)

    //handle static files, perhaps better left to nginx in future?
    fs := http.FileServer(http.Dir("static"))
    http.Handle("/static/", http.StripPrefix("/static/", fs))

    http.ListenAndServe(":8080", nil)
}
<commit_msg>added port logic<commit_after>package main

import (
    "os"
    "strconv"
    //"fmt"
    "log"
    "net/http"
    "html/template"
)

var templates = template.Must(template.ParseGlob("templates/*"))

func handler(w http.ResponseWriter, r *http.Request) {
    title := r.URL.Path[1:]
    err := templates.ExecuteTemplate(w, "index", title)

    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
}

func main() {
    http.HandleFunc("/", handler)

    //handle static files, perhaps better left to nginx in future?
    fs := http.FileServer(http.Dir("static"))
    http.Handle("/static/", http.StripPrefix("/static/", fs))

    //default port, but allow command line argument to override port
    port := ":8080"
    if len(os.Args) > 1 {
        tport := os.Args[1]
        i, err := strconv.Atoi(tport)
        if err != nil || i < 0 || i > 65535 {
            log.Printf("Error: specified port %q is invalid.\n", tport)
            log.Printf("Defaulting to port 8080.\n")
        } else {
            port = ":" + tport
        }
    }

    log.Fatal(http.ListenAndServe(port, nil))
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strings"
)

var address = flag.String("address", ":8080", "address to listen on")

func check(err error) {
	if err != nil {
		panic(err)
	}
}

func main() {
	flag.Parse()

	configureHooks()

	http.HandleFunc("/hook", handleRoot)
	log.Fatal(http.ListenAndServe(*address, nil))

}

func configureHooks() {
	github_user := os.Getenv("GITHUB_USER")
	github_password := os.Getenv("GITHUB_PASSWORD")

	json := `{
	"name": "web",
	"config": {"url": "http://services.scraperwiki.com/hook",
		"content_type": "json"},
	"events": ["push", "issues", "issue_comment",
		"commit_comment", "create", "delete",
		"pull_request", "pull_request_review_comment",
		"gollum", "watch", "release", "fork", "member",
		"public", "team_add", "status"],
	"active": true
	}`

	endpoint := "https://" + github_user + ":" + github_password + "@" + "api.github.com"

	repos := []string{
		"scraperwiki/custard",
		"scraperwiki/tang",
	}

	for _, repo := range repos {

		buffer := strings.NewReader(json)
		resp, err := http.Post(endpoint+"/repos/"+repo+"/hooks", "application/json", buffer)
		check(err)

		log.Println("Rate Limit:", resp.Header["X-Ratelimit-Remaining"][0])

		switch resp.StatusCode {
		default:
			response, err := ioutil.ReadAll(resp.Body)
			check(err)

			log.Print(string(response))

		case 422:
			log.Println("Already hooked for", repo)
		}
	}

}

func handleRoot(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Hello, world!\n")

	request, err := ioutil.ReadAll(r.Body)
	check(err)

	var dst bytes.Buffer
	r.Header.Write(&dst)
	log.Println("Incoming request headers: ", string(dst.Bytes()))

	dst.Reset()
	err = json.Indent(&dst, request, "", "  ")
	check(err)

	var doc_ interface{}
	err = json.Unmarshal(dst.Bytes(), &doc_)
	check(err)
	doc := doc_.(map[string]interface{})

	log.Println("Incoming request:", string(dst.Bytes()))

	switch eventType := r.Header["X-Github-Event"][0]; eventType {
	case "push":

		log.Println("Pushed")
		ref := doc["ref"].(string)
		url := doc["repository"].(map[string]interface{})["url"].(string)
		after := doc["after"].(string)

		log.Println("Push to", url, ref, "after", after)

	default:
		log.Println("Unhandled event:", eventType)
	}

}
<commit_msg>Make list of repos to hook configurable (so that I can set it to '')<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strings"
)

var address = flag.String("address", ":8080", "address to listen on")
var repositories = flag.String("repositories", "scraperwiki/tang", "colon separated list of repositories to watch")

func check(err error) {
	if err != nil {
		panic(err)
	}
}

func main() {
	flag.Parse()

	configureHooks()

	http.HandleFunc("/hook", handleRoot)

	log.Fatal(http.ListenAndServe(*address, nil))
}

func configureHooks() {
	github_user := os.Getenv("GITHUB_USER")
	github_password := os.Getenv("GITHUB_PASSWORD")

	json := `{
	"name": "web",
	"config": {"url": "http://services.scraperwiki.com/hook",
		"content_type": "json"},
	"events": ["push", "issues", "issue_comment",
		"commit_comment", "create", "delete",
		"pull_request", "pull_request_review_comment",
		"gollum", "watch", "release", "fork", "member",
		"public", "team_add", "status"],
	"active": true
	}`

	endpoint := "https://" + github_user + ":" + github_password + "@" + "api.github.com"

	repos := strings.Split(*repositories, ":")

	for _, repo := range repos {

		buffer := strings.NewReader(json)
		resp, err := http.Post(endpoint+"/repos/"+repo+"/hooks", "application/json", buffer)
		check(err)

		log.Println("Rate Limit:", resp.Header["X-Ratelimit-Remaining"][0])

		switch resp.StatusCode {
		default:
			response, err := ioutil.ReadAll(resp.Body)
			check(err)

			log.Print(string(response))

		case 422:
			log.Println("Already hooked for", repo)
		}
	}

}

func handleRoot(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Hello, world!\n")

	request, err := ioutil.ReadAll(r.Body)
	check(err)

	var dst bytes.Buffer
	r.Header.Write(&dst)
	log.Println("Incoming request headers: ", string(dst.Bytes()))

	dst.Reset()
	err = json.Indent(&dst, request, "", "  ")
	check(err)

	var doc_ interface{}
	err = json.Unmarshal(dst.Bytes(), &doc_)
	check(err)
	doc := doc_.(map[string]interface{})

	log.Println("Incoming request:", string(dst.Bytes()))

	switch eventType := r.Header["X-Github-Event"][0]; eventType {
	case "push":

		log.Println("Pushed")
		ref := doc["ref"].(string)
		url := doc["repository"].(map[string]interface{})["url"].(string)
		after := doc["after"].(string)

		log.Println("Push to", url, ref, "after", after)

	default:
		log.Println("Unhandled event:", eventType)
	}

}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"net/http"
	"os"
)

const (
	usage = `
Usage: curl http://127.0.0.1:8080/[endpoint]

    Perform HTTP request against the API for a specific action.

Endpoints:

    /            show this message
    /health      check health status
    /hostname    display hostname
`

	cowsay = `
 _______________________________________
|  You are only young once, but you can |
|  stay immature indefinitely.          |
 ---------------------------------------
    \   ^__^
     \  (oo)\_______
        (__)\       )\/\
            ||----w |
            ||     ||
`
)

func endpointHandler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "%s", usage)
	log.Printf("%s", r.URL.Path)
}

func hostnameHandler(w http.ResponseWriter, r *http.Request) {
	hostname, _ := os.Hostname()
	fmt.Fprintf(w, "Hostname: %s\n", hostname)
	log.Printf("%s", r.URL.Path)
}

func cowsayHandler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "%s", cowsay)
	log.Printf("%s", r.URL.Path)

}

func healthCheckHandler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "OK")
	log.Printf("%s", r.URL.Path)
}

func main() {

	http.HandleFunc("/", endpointHandler)
	http.HandleFunc("/cow", cowsayHandler)
	http.HandleFunc("/health", healthCheckHandler)
	http.HandleFunc("/hostname", hostnameHandler)

	http.ListenAndServe(":8080", nil)

}
<commit_msg>add cowsay endpoint to health<commit_after>package main

import (
	"fmt"
	"log"
	"net/http"
	"os"
)

const (
	usage = `
Usage: curl http://127.0.0.1:8080/[endpoint]

    Perform HTTP request against the API for a specific action.

Endpoints:

    /            show this message
	/cowsay      talking cow
    /health      check health status
    /hostname    display hostname
`

	cowsay = `
 _______________________________________
|  You are only young once, but you can |
|  stay immature indefinitely.          |
 ---------------------------------------
    \   ^__^
     \  (oo)\_______
        (__)\       )\/\
            ||----w |
            ||     ||
`
)

func endpointHandler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "%s", usage)
	log.Printf("%s", r.URL.Path)
}

func hostnameHandler(w http.ResponseWriter, r *http.Request) {
	hostname, _ := os.Hostname()
	fmt.Fprintf(w, "Hostname: %s\n", hostname)
	log.Printf("%s", r.URL.Path)
}

func cowsayHandler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "%s", cowsay)
	log.Printf("%s", r.URL.Path)

}

func healthCheckHandler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "OK")
	log.Printf("%s", r.URL.Path)
}

func main() {

	http.HandleFunc("/", endpointHandler)
	http.HandleFunc("/cowsay", cowsayHandler)
	http.HandleFunc("/health", healthCheckHandler)
	http.HandleFunc("/hostname", hostnameHandler)

	http.ListenAndServe(":8080", nil)

}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"math"
	"net/http"
	"net/url"
	"os"
	"path"
	"path/filepath"
	"strings"
	"time"
)

const (
	version = "0.8.8"
)

func init() {
	flag.Usage = func() {
		h := "Usage:\n"
		h += "  bozr [OPTIONS] (DIR|FILE)\n\n"

		h += "Options:\n"
		h += "  -d, --debug		Enable debug mode\n"
		h += "  -H, --host		Server to test\n"
		h += "  -h, --help		Print usage\n"
		h += "  -i, --info		Enable info mode. Print request and response details\n"
		h += "      --junit		Enable junit xml reporter\n"
		h += "      --junit-output	Destination for junit report files\n"
		h += "  -v, --version		Print version information and quit\n\n"

		h += "Examples:\n"
		h += "  bozr ./examples\n"
		h += "  bozr -H http://example.com ./examples \n"

		fmt.Fprintf(os.Stderr, h)
	}
}

var (
	suiteDir        string
	hostFlag        string
	infoFlag        bool
	debugFlag       bool
	helpFlag        bool
	versionFlag     bool
	junitFlag       bool
	junitOutputFlag string

	info  *log.Logger
	debug *log.Logger
)

const suiteExt = ".suite.json"

func initLogger() {
	infoHandler := ioutil.Discard
	debugHandler := ioutil.Discard

	if infoFlag {
		infoHandler = os.Stdout
	}

	if debugFlag {
		debugHandler = os.Stdout
	}

	info = log.New(infoHandler, "", 0)
	debug = log.New(debugHandler, "DEBUG: ", log.Ltime|log.Lshortfile)
}

func main() {
	flag.BoolVar(&debugFlag, "d", false, "Enable debug mode.")
	flag.BoolVar(&debugFlag, "debug", false, "Enable debug mode")

	flag.BoolVar(&infoFlag, "i", false, "Enable info mode. Print request and response details.")
	flag.BoolVar(&infoFlag, "info", false, "Enable info mode. Print request and response details.")

	flag.StringVar(&hostFlag, "H", "", "Test server address. Example: http://example.com/api.")

	flag.BoolVar(&helpFlag, "h", false, "Print usage")
	flag.BoolVar(&helpFlag, "help", false, "Print usage")

	flag.BoolVar(&versionFlag, "v", false, "Print version information and quit")
	flag.BoolVar(&versionFlag, "version", false, "Print version information and quit")

	flag.BoolVar(&junitFlag, "junit", false, "Enable junit xml reporter")
	flag.StringVar(&junitOutputFlag, "junit-output", "./report", "Destination for junit report files. Default ")

	flag.Parse()

	initLogger()

	if versionFlag {
		fmt.Println("bozr version " + version)
		return
	}

	if helpFlag {
		flag.Usage()
		return
	}

	if len(hostFlag) > 0 {
		_, err := url.ParseRequestURI(hostFlag)
		if err != nil {
			terminate("Invalid host is specified.")
			return
		}
	}

	src := flag.Arg(0)

	if src == "" {
		terminate("You must specify a directory or file with tests.")
		flag.Usage()
		return
	}

	// check specified source dir/file exists
	_, err := os.Lstat(src)
	if err != nil {
		terminate(err.Error())
		return
	}

	err = ValidateSuites(src, suiteExt)
	if err != nil {
		terminate("One or more test suites are invalid.", err.Error())
		return
	}

	loader := NewSuiteLoader(src, suiteExt)

	reporters := []Reporter{NewConsoleReporter()}
	if junitFlag {
		path, _ := filepath.Abs(junitOutputFlag)
		reporters = append(reporters, NewJUnitReporter(path))
	}
	reporter := NewMultiReporter(reporters...)
	reporter.Init()

	// test case runner?
	for suite := range loader {
		for _, testCase := range suite.Cases {

			result := TestResult{
				Suite:     suite,
				Case:      testCase,
				ExecFrame: TimeFrame{Start: time.Now()},
			}

			if testCase.Ignore != nil {
				result.Skipped = true
				result.SkippedMsg = *testCase.Ignore
				reporter.Report(result)
				continue
			}

			rememberedMap := make(map[string]interface{})
			for _, c := range testCase.Calls {
				addAll(c.Args, rememberedMap)
				terr := call(suite, testCase, c, rememberedMap)
				if terr != nil {
					result.Error = terr
					break
				}
			}

			result.ExecFrame.End = time.Now()

			reporter.Report(result)
		}
	}

	reporter.Flush()
}

func addAll(src, target map[string]interface{}) {
	for key, val := range src {
		target[key] = val
	}
}

func call(testSuite TestSuite, testCase TestCase, call Call, rememberMap map[string]interface{}) *TError {
	debug.Printf("Starting call: %s - %s", testSuite.Name, testCase.Name)
	terr := &TError{}

	on := call.On

	dat := []byte(on.Body)
	if on.BodyFile != "" {
		uri, err := toAbsPath(testSuite.Dir, on.BodyFile)
		if err != nil {
			terr.Cause = err
			return terr
		}

		if d, err := ioutil.ReadFile(uri); err == nil {
			dat = d
		} else {
			terr.Cause = fmt.Errorf("Can't read body file: %s", err.Error())
			return terr
		}
	}

	req, err := populateRequest(on, string(dat), rememberMap)
	if err != nil {
		terr.Cause = err
		return terr
	}

	printRequestInfo(req, dat)

	client := &http.Client{}

	resp, err := client.Do(req)

	if err != nil {
		debug.Print("Error when sending request", err)
		terr.Cause = err
		return terr
	}

	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		debug.Print("Error reading response")
		terr.Cause = err
		return terr
	}

	testResp := Response{http: *resp, body: body}
	terr.Resp = testResp

	info.Println(strings.Repeat("-", 50))
	info.Println(testResp.ToString())
	info.Println("")

	exps, err := expectations(call, testSuite.Dir)
	if err != nil {
		terr.Cause = err
		return terr
	}

	for _, exp := range exps {
		checkErr := exp.check(&testResp)
		if checkErr != nil {
			terr.Cause = checkErr
			return terr
		}
	}

	err = rememberBody(&testResp, call.Remember.Body, rememberMap)
	debug.Print("Remember: ", rememberMap)
	if err != nil {
		debug.Print("Error remember")
		terr.Cause = err
		return terr
	}

	rememberHeaders(testResp.http.Header, call.Remember.Headers, rememberMap)

	return nil
}

func populateRequest(on On, body string, rememberMap map[string]interface{}) (*http.Request, error) {

	urlStr, err := urlPrefix(populateRememberedVars(on.URL, rememberMap))
	if err != nil {
		return nil, errors.New("Cannot create request. Invalid url: " + on.URL)
	}

	body = populateRememberedVars(body, rememberMap)
	dat := []byte(body)

	req, err := http.NewRequest(on.Method, urlStr, bytes.NewBuffer(dat))
	if err != nil {
		return nil, err
	}

	for key, value := range on.Headers {
		req.Header.Add(key, populateRememberedVars(value, rememberMap))
	}

	q := req.URL.Query()
	for key, value := range on.Params {
		q.Add(key, populateRememberedVars(value, rememberMap))
	}
	req.URL.RawQuery = q.Encode()

	return req, nil
}

func urlPrefix(p string) (string, error) {
	if strings.HasPrefix(p, "http://") || strings.HasPrefix(p, "https://") {
		return p, nil
	}

	return concatURL(hostFlag, p)
}

func concatURL(base string, p string) (string, error) {
	baseURL, err := url.ParseRequestURI(base)
	if err != nil {
		return "", err
	}
	return baseURL.Scheme + "://" + baseURL.Host + path.Join(baseURL.Path, p), nil
}

func populateRememberedVars(str string, rememberMap map[string]interface{}) string {
	res := str
	for varName, val := range rememberMap {
		placeholder := "{" + varName + "}"
		res = strings.Replace(res, placeholder, toString(val), -1)
	}
	return res
}

// toString returns value suitable to insert as an argument
// if value if a float where decimal part is zero - convert to int
func toString(rw interface{}) string {
	var sv interface{} = rw
	if fv, ok := rw.(float64); ok {
		_, frac := math.Modf(fv)
		if frac == 0 {
			sv = int(fv)
		}
	}

	return fmt.Sprintf("%v", sv)
}

func expectations(call Call, srcDir string) ([]ResponseExpectation, error) {
	var exps []ResponseExpectation
	if call.Expect.StatusCode != 0 {
		exps = append(exps, StatusCodeExpectation{statusCode: call.Expect.StatusCode})
	}

	if call.Expect.hasSchema() {
		var (
			schemeURI string
			err       error
		)

		if call.Expect.BodySchemaFile != "" {
			schemeURI, err = toAbsPath(srcDir, call.Expect.BodySchemaFile)
			if err != nil {
				return nil, err
			}
			schemeURI = "file:///" + schemeURI
		}

		if call.Expect.BodySchemaURI != "" {
			isHTTP := strings.HasPrefix(call.Expect.BodySchemaURI, "http://")
			isHTTPS := strings.HasPrefix(call.Expect.BodySchemaURI, "https://")
			if !(isHTTP || isHTTPS) {
				schemeURI = hostFlag + call.Expect.BodySchemaURI
			} else {
				schemeURI = call.Expect.BodySchemaURI
			}
		}
		exps = append(exps, BodySchemaExpectation{schemaURI: schemeURI})
	}

	if len(call.Expect.Body) > 0 {
		exps = append(exps, BodyExpectation{pathExpectations: call.Expect.Body})
	}

	if len(call.Expect.Absent) > 0 {
		exps = append(exps, AbsentExpectation{paths: call.Expect.Absent})
	}

	if len(call.Expect.Headers) > 0 {
		for k, v := range call.Expect.Headers {
			exps = append(exps, HeaderExpectation{Name: k, Value: v})
		}
	}

	if call.Expect.ContentType != "" {
		exps = append(exps, ContentTypeExpectation{call.Expect.ContentType})
	}

	// and so on
	return exps, nil
}

func toAbsPath(srcDir string, assetPath string) (string, error) {
	if filepath.IsAbs(assetPath) {
		// ignore srcDir
		return assetPath, nil
	}

	uri, err := filepath.Abs(filepath.Join(suiteDir, srcDir, assetPath))
	if err != nil {
		return "", errors.New("Invalid file path: " + assetPath)
	}

	return filepath.ToSlash(uri), nil
}

func rememberBody(resp *Response, remember map[string]string, rememberedMap map[string]interface{}) (err error) {

	for varName, pathLine := range remember {
		body, err := resp.Body()
		if err != nil {
			debug.Print("Can't parse response body to Map for [remember]")
			return err
		}

		if rememberVar, err := GetByPath(body, pathLine); err == nil {
			rememberedMap[varName] = rememberVar
		} else {
			strErr := fmt.Sprintf("Remembered value not found, path: %v", pathLine)
			err = errors.New(strErr)
		}
		//fmt.Printf("v: %v\n", getByPath(bodyMap, b...))
	}

	return err
}

func rememberHeaders(header http.Header, remember map[string]string, rememberedMap map[string]interface{}) {
	for valueName, headerName := range remember {
		value := header.Get(headerName)
		if value == "" {
			continue
		}

		rememberedMap[valueName] = value
	}
}

func printRequestInfo(req *http.Request, body []byte) {
	info.Println()
	info.Printf("%s %s %s\n", req.Method, req.URL.String(), req.Proto)

	if len(req.Header) > 0 {
		info.Println()
	}

	for k, v := range req.Header {
		info.Printf("%s: %s", k, strings.Join(v, " "))
	}
	info.Println()

	if len(body) > 0 {
		info.Printf(string(body))
	}
}

func terminate(msgLines ...string) {
	for _, line := range msgLines {
		fmt.Fprintln(os.Stderr, line)
	}

	os.Exit(1)
}
<commit_msg>fix asset files lookup [regression]<commit_after>package main

import (
	"bytes"
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"math"
	"net/http"
	"net/url"
	"os"
	"path"
	"path/filepath"
	"strings"
	"time"
)

const (
	version = "0.8.8"
)

func init() {
	flag.Usage = func() {
		h := "Usage:\n"
		h += "  bozr [OPTIONS] (DIR|FILE)\n\n"

		h += "Options:\n"
		h += "  -d, --debug		Enable debug mode\n"
		h += "  -H, --host		Server to test\n"
		h += "  -h, --help		Print usage\n"
		h += "  -i, --info		Enable info mode. Print request and response details\n"
		h += "      --junit		Enable junit xml reporter\n"
		h += "      --junit-output	Destination for junit report files\n"
		h += "  -v, --version		Print version information and quit\n\n"

		h += "Examples:\n"
		h += "  bozr ./examples\n"
		h += "  bozr -H http://example.com ./examples \n"

		fmt.Fprintf(os.Stderr, h)
	}
}

var (
	suitesDir       string
	hostFlag        string
	infoFlag        bool
	debugFlag       bool
	helpFlag        bool
	versionFlag     bool
	junitFlag       bool
	junitOutputFlag string

	info  *log.Logger
	debug *log.Logger
)

const suiteExt = ".suite.json"

func initLogger() {
	infoHandler := ioutil.Discard
	debugHandler := ioutil.Discard

	if infoFlag {
		infoHandler = os.Stdout
	}

	if debugFlag {
		debugHandler = os.Stdout
	}

	info = log.New(infoHandler, "", 0)
	debug = log.New(debugHandler, "DEBUG: ", log.Ltime|log.Lshortfile)
}

func main() {
	flag.BoolVar(&debugFlag, "d", false, "Enable debug mode.")
	flag.BoolVar(&debugFlag, "debug", false, "Enable debug mode")

	flag.BoolVar(&infoFlag, "i", false, "Enable info mode. Print request and response details.")
	flag.BoolVar(&infoFlag, "info", false, "Enable info mode. Print request and response details.")

	flag.StringVar(&hostFlag, "H", "", "Test server address. Example: http://example.com/api.")

	flag.BoolVar(&helpFlag, "h", false, "Print usage")
	flag.BoolVar(&helpFlag, "help", false, "Print usage")

	flag.BoolVar(&versionFlag, "v", false, "Print version information and quit")
	flag.BoolVar(&versionFlag, "version", false, "Print version information and quit")

	flag.BoolVar(&junitFlag, "junit", false, "Enable junit xml reporter")
	flag.StringVar(&junitOutputFlag, "junit-output", "./report", "Destination for junit report files. Default ")

	flag.Parse()

	initLogger()

	if versionFlag {
		fmt.Println("bozr version " + version)
		return
	}

	if helpFlag {
		flag.Usage()
		return
	}

	if len(hostFlag) > 0 {
		_, err := url.ParseRequestURI(hostFlag)
		if err != nil {
			terminate("Invalid host is specified.")
			return
		}
	}

	suitesDir = flag.Arg(0)

	if suitesDir == "" {
		terminate("You must specify a directory or file with tests.")
		flag.Usage()
		return
	}

	// check specified source dir/file exists
	_, err := os.Lstat(suitesDir)
	if err != nil {
		terminate(err.Error())
		return
	}

	err = ValidateSuites(suitesDir, suiteExt)
	if err != nil {
		terminate("One or more test suites are invalid.", err.Error())
		return
	}

	loader := NewSuiteLoader(suitesDir, suiteExt)

	reporters := []Reporter{NewConsoleReporter()}
	if junitFlag {
		path, _ := filepath.Abs(junitOutputFlag)
		reporters = append(reporters, NewJUnitReporter(path))
	}
	reporter := NewMultiReporter(reporters...)
	reporter.Init()

	// test case runner?
	for suite := range loader {
		for _, testCase := range suite.Cases {

			result := TestResult{
				Suite:     suite,
				Case:      testCase,
				ExecFrame: TimeFrame{Start: time.Now()},
			}

			if testCase.Ignore != nil {
				result.Skipped = true
				result.SkippedMsg = *testCase.Ignore
				reporter.Report(result)
				continue
			}

			rememberedMap := make(map[string]interface{})
			for _, c := range testCase.Calls {
				addAll(c.Args, rememberedMap)
				terr := call(suite, testCase, c, rememberedMap)
				if terr != nil {
					result.Error = terr
					break
				}
			}

			result.ExecFrame.End = time.Now()

			reporter.Report(result)
		}
	}

	reporter.Flush()
}

func addAll(src, target map[string]interface{}) {
	for key, val := range src {
		target[key] = val
	}
}

func call(testSuite TestSuite, testCase TestCase, call Call, rememberMap map[string]interface{}) *TError {
	debug.Printf("Starting call: %s - %s", testSuite.Name, testCase.Name)
	terr := &TError{}

	on := call.On

	dat := []byte(on.Body)
	if on.BodyFile != "" {
		uri, err := toAbsPath(testSuite.Dir, on.BodyFile)
		if err != nil {
			terr.Cause = err
			return terr
		}

		if d, err := ioutil.ReadFile(uri); err == nil {
			dat = d
		} else {
			terr.Cause = fmt.Errorf("Can't read body file: %s", err.Error())
			return terr
		}
	}

	req, err := populateRequest(on, string(dat), rememberMap)
	if err != nil {
		terr.Cause = err
		return terr
	}

	printRequestInfo(req, dat)

	client := &http.Client{}

	resp, err := client.Do(req)

	if err != nil {
		debug.Print("Error when sending request", err)
		terr.Cause = err
		return terr
	}

	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		debug.Print("Error reading response")
		terr.Cause = err
		return terr
	}

	testResp := Response{http: *resp, body: body}
	terr.Resp = testResp

	info.Println(strings.Repeat("-", 50))
	info.Println(testResp.ToString())
	info.Println("")

	exps, err := expectations(call, testSuite.Dir)
	if err != nil {
		terr.Cause = err
		return terr
	}

	for _, exp := range exps {
		checkErr := exp.check(&testResp)
		if checkErr != nil {
			terr.Cause = checkErr
			return terr
		}
	}

	err = rememberBody(&testResp, call.Remember.Body, rememberMap)
	debug.Print("Remember: ", rememberMap)
	if err != nil {
		debug.Print("Error remember")
		terr.Cause = err
		return terr
	}

	rememberHeaders(testResp.http.Header, call.Remember.Headers, rememberMap)

	return nil
}

func populateRequest(on On, body string, rememberMap map[string]interface{}) (*http.Request, error) {

	urlStr, err := urlPrefix(populateRememberedVars(on.URL, rememberMap))
	if err != nil {
		return nil, errors.New("Cannot create request. Invalid url: " + on.URL)
	}

	body = populateRememberedVars(body, rememberMap)
	dat := []byte(body)

	req, err := http.NewRequest(on.Method, urlStr, bytes.NewBuffer(dat))
	if err != nil {
		return nil, err
	}

	for key, value := range on.Headers {
		req.Header.Add(key, populateRememberedVars(value, rememberMap))
	}

	q := req.URL.Query()
	for key, value := range on.Params {
		q.Add(key, populateRememberedVars(value, rememberMap))
	}
	req.URL.RawQuery = q.Encode()

	return req, nil
}

func urlPrefix(p string) (string, error) {
	if strings.HasPrefix(p, "http://") || strings.HasPrefix(p, "https://") {
		return p, nil
	}

	return concatURL(hostFlag, p)
}

func concatURL(base string, p string) (string, error) {
	baseURL, err := url.ParseRequestURI(base)
	if err != nil {
		return "", err
	}
	return baseURL.Scheme + "://" + baseURL.Host + path.Join(baseURL.Path, p), nil
}

func populateRememberedVars(str string, rememberMap map[string]interface{}) string {
	res := str
	for varName, val := range rememberMap {
		placeholder := "{" + varName + "}"
		res = strings.Replace(res, placeholder, toString(val), -1)
	}
	return res
}

// toString returns value suitable to insert as an argument
// if value if a float where decimal part is zero - convert to int
func toString(rw interface{}) string {
	var sv interface{} = rw
	if fv, ok := rw.(float64); ok {
		_, frac := math.Modf(fv)
		if frac == 0 {
			sv = int(fv)
		}
	}

	return fmt.Sprintf("%v", sv)
}

func expectations(call Call, suitePath string) ([]ResponseExpectation, error) {
	var exps []ResponseExpectation
	if call.Expect.StatusCode != 0 {
		exps = append(exps, StatusCodeExpectation{statusCode: call.Expect.StatusCode})
	}

	if call.Expect.hasSchema() {
		var (
			schemeURI string
			err       error
		)

		if call.Expect.BodySchemaFile != "" {
			schemeURI, err = toAbsPath(suitePath, call.Expect.BodySchemaFile)
			if err != nil {
				return nil, err
			}
			schemeURI = "file:///" + schemeURI
		}

		if call.Expect.BodySchemaURI != "" {
			isHTTP := strings.HasPrefix(call.Expect.BodySchemaURI, "http://")
			isHTTPS := strings.HasPrefix(call.Expect.BodySchemaURI, "https://")
			if !(isHTTP || isHTTPS) {
				schemeURI = hostFlag + call.Expect.BodySchemaURI
			} else {
				schemeURI = call.Expect.BodySchemaURI
			}
		}
		exps = append(exps, BodySchemaExpectation{schemaURI: schemeURI})
	}

	if len(call.Expect.Body) > 0 {
		exps = append(exps, BodyExpectation{pathExpectations: call.Expect.Body})
	}

	if len(call.Expect.Absent) > 0 {
		exps = append(exps, AbsentExpectation{paths: call.Expect.Absent})
	}

	if len(call.Expect.Headers) > 0 {
		for k, v := range call.Expect.Headers {
			exps = append(exps, HeaderExpectation{Name: k, Value: v})
		}
	}

	if call.Expect.ContentType != "" {
		exps = append(exps, ContentTypeExpectation{call.Expect.ContentType})
	}

	// and so on
	return exps, nil
}

func toAbsPath(suitePath string, assetPath string) (string, error) {
	debug.Printf("Building absolute path using: suiteDir: %s, srcDir: %s, assetPath: %s", suitesDir, suitePath, assetPath)
	if filepath.IsAbs(assetPath) {
		// ignore srcDir
		return assetPath, nil
	}

	uri, err := filepath.Abs(filepath.Join(suitesDir, suitePath, assetPath))
	if err != nil {
		return "", errors.New("Invalid file path: " + assetPath)
	}

	return filepath.ToSlash(uri), nil
}

func rememberBody(resp *Response, remember map[string]string, rememberedMap map[string]interface{}) (err error) {

	for varName, pathLine := range remember {
		body, err := resp.Body()
		if err != nil {
			debug.Print("Can't parse response body to Map for [remember]")
			return err
		}

		if rememberVar, err := GetByPath(body, pathLine); err == nil {
			rememberedMap[varName] = rememberVar
		} else {
			strErr := fmt.Sprintf("Remembered value not found, path: %v", pathLine)
			err = errors.New(strErr)
		}
		//fmt.Printf("v: %v\n", getByPath(bodyMap, b...))
	}

	return err
}

func rememberHeaders(header http.Header, remember map[string]string, rememberedMap map[string]interface{}) {
	for valueName, headerName := range remember {
		value := header.Get(headerName)
		if value == "" {
			continue
		}

		rememberedMap[valueName] = value
	}
}

func printRequestInfo(req *http.Request, body []byte) {
	info.Println()
	info.Printf("%s %s %s\n", req.Method, req.URL.String(), req.Proto)

	if len(req.Header) > 0 {
		info.Println()
	}

	for k, v := range req.Header {
		info.Printf("%s: %s", k, strings.Join(v, " "))
	}
	info.Println()

	if len(body) > 0 {
		info.Printf(string(body))
	}
}

func terminate(msgLines ...string) {
	for _, line := range msgLines {
		fmt.Fprintln(os.Stderr, line)
	}

	os.Exit(1)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"time"

	"github.com/acmacalister/gatt"
)

func main() {

	srv := gatt.NewServer(gatt.Name("gophergatt"))
	svc := srv.AddService(gatt.MustParseUUID("09fc95c0-c111-11e3-9904-0002a5d5c51b"))

	// Add a read characteristic that prints how many times it has been read
	n := 0
	rchar := svc.AddCharacteristic(gatt.MustParseUUID("11fac9e0-c111-11e3-9246-0002a5d5c51b"))
	rchar.HandleRead(
		gatt.ReadHandlerFunc(
			func(resp gatt.ReadResponseWriter, req *gatt.ReadRequest) {
				fmt.Fprintf(resp, "count: %d", n)
				n++
			}),
	)

	// Add a write characteristic that logs when written to
	wchar := svc.AddCharacteristic(gatt.MustParseUUID("16fe0d80-c111-11e3-b8c8-0002a5d5c51b"))
	wchar.HandleWriteFunc(
		func(r gatt.Request, data []byte) (status byte) {
			log.Println("Wrote:", string(data))
			return gatt.StatusSuccess
		})

	// Add a notify characteristic that updates once a second
	nchar := svc.AddCharacteristic(gatt.MustParseUUID("1c927b50-c116-11e3-8a33-0800200c9a66"))
	nchar.HandleNotifyFunc(
		func(r gatt.Request, n gatt.Notifier) {
			go func() {
				count := 0
				for !n.Done() {
					fmt.Fprintf(n, "Count: %d", count)
					count++
					time.Sleep(time.Second)
				}
			}()
		})

	fmt.Println("advertising...")
	// Start the server
	log.Fatal(srv.AdvertiseAndServe())
}

// c := &serial.Config{Name: "/dev/ttyMFD1", Baud: 9600}
// s, err := serial.OpenPort(c)
// if err != nil {
// 	log.Fatal(err)
// }

// go func() {
// 	for {
// 		reader := bufio.NewReader(os.Stdin)
// 		fmt.Print("Enter text: ")
// 		text, _ := reader.ReadString('\n')
// 		_, err := s.Write([]byte(text))
// 		if err != nil {
// 			log.Fatal(err)
// 		}
// 	}
// }()

// for {
// 	buf := make([]byte, 128)
// 	n, err := s.Read(buf)
// 	if err != nil {
// 		log.Fatal(err)
// 	}
// 	log.Println("stuff:", string(buf[:n]))
// }
<commit_msg>use paypal instead of fork<commit_after>package main

import (
	"fmt"
	"log"
	"time"

	"github.com/paypal/gatt"
)

func main() {

	srv := gatt.NewServer(gatt.Name("gophergatt"))
	svc := srv.AddService(gatt.MustParseUUID("09fc95c0-c111-11e3-9904-0002a5d5c51b"))

	// Add a read characteristic that prints how many times it has been read
	n := 0
	rchar := svc.AddCharacteristic(gatt.MustParseUUID("11fac9e0-c111-11e3-9246-0002a5d5c51b"))
	rchar.HandleRead(
		gatt.ReadHandlerFunc(
			func(resp gatt.ReadResponseWriter, req *gatt.ReadRequest) {
				fmt.Fprintf(resp, "count: %d", n)
				n++
			}),
	)

	// Add a write characteristic that logs when written to
	wchar := svc.AddCharacteristic(gatt.MustParseUUID("16fe0d80-c111-11e3-b8c8-0002a5d5c51b"))
	wchar.HandleWriteFunc(
		func(r gatt.Request, data []byte) (status byte) {
			log.Println("Wrote:", string(data))
			return gatt.StatusSuccess
		})

	// Add a notify characteristic that updates once a second
	nchar := svc.AddCharacteristic(gatt.MustParseUUID("1c927b50-c116-11e3-8a33-0800200c9a66"))
	nchar.HandleNotifyFunc(
		func(r gatt.Request, n gatt.Notifier) {
			go func() {
				count := 0
				for !n.Done() {
					fmt.Fprintf(n, "Count: %d", count)
					count++
					time.Sleep(time.Second)
				}
			}()
		})

	fmt.Println("advertising...")
	// Start the server
	log.Fatal(srv.AdvertiseAndServe())
}

// c := &serial.Config{Name: "/dev/ttyMFD1", Baud: 9600}
// s, err := serial.OpenPort(c)
// if err != nil {
// 	log.Fatal(err)
// }

// go func() {
// 	for {
// 		reader := bufio.NewReader(os.Stdin)
// 		fmt.Print("Enter text: ")
// 		text, _ := reader.ReadString('\n')
// 		_, err := s.Write([]byte(text))
// 		if err != nil {
// 			log.Fatal(err)
// 		}
// 	}
// }()

// for {
// 	buf := make([]byte, 128)
// 	n, err := s.Read(buf)
// 	if err != nil {
// 		log.Fatal(err)
// 	}
// 	log.Println("stuff:", string(buf[:n]))
// }
<|endoftext|>


<commit_before>package main

import (
	"context"
	"net/http"
	"os"
	"runtime"
	"time"

	arg "github.com/alexflint/go-arg"
	"github.com/digitalocean/godo"
	"github.com/go-kit/kit/log"
	"github.com/go-kit/kit/log/level"
	"github.com/joho/godotenv"
	"github.com/metalmatze/digitalocean_exporter/collector"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"golang.org/x/oauth2"
)

var (
	// Version of digitalocean_exporter.
	Version string
	// Revision or Commit this binary was built from.
	Revision string
	// BuildDate this binary was built.
	BuildDate string
	// GoVersion running this binary.
	GoVersion = runtime.Version()
	// StartTime has the time this was started.
	StartTime = time.Now()
)

// Config gets its content from env and passes it on to different packages
type Config struct {
	DigitalOceanToken string `arg:"env:DIGITALOCEAN_TOKEN"`
	WebAddr           string `arg:"env:WEB_ADDR"`
	WebPath           string `arg:"env:WEB_PATH"`
}

// Token returns a token or an error.
func (c Config) Token() (*oauth2.Token, error) {
	return &oauth2.Token{AccessToken: c.DigitalOceanToken}, nil
}

func main() {
	_ = godotenv.Load()

	c := Config{
		WebPath: "/metrics",
		WebAddr: ":9212",
	}
	arg.MustParse(&c)

	if c.DigitalOceanToken == "" {
		panic("DigitalOcean Token is required")
	}

	logger := log.NewLogfmtLogger(log.NewSyncWriter(os.Stderr))
	logger = level.NewFilter(logger, level.AllowDebug())
	logger = log.With(logger,
		"ts", log.DefaultTimestampUTC,
		"caller", log.DefaultCaller,
	)

	level.Info(logger).Log(
		"msg", "starting digitalocean_snapper",
		"version", Version,
		"revision", Revision,
		"buildDate", BuildDate,
		"goVersion", GoVersion,
	)

	oauthClient := oauth2.NewClient(context.TODO(), c)
	client := godo.NewClient(oauthClient)

	prometheus.MustRegister(collector.NewAccountCollector(logger, client))
	prometheus.MustRegister(collector.NewDropletCollector(logger, client))
	prometheus.MustRegister(collector.NewExporterCollector(logger, Version, Revision, BuildDate, GoVersion, StartTime))
	prometheus.MustRegister(collector.NewFloatingIPCollector(logger, client))
	prometheus.MustRegister(collector.NewImageCollector(logger, client))
	prometheus.MustRegister(collector.NewKeyCollector(logger, client))
	prometheus.MustRegister(collector.NewSnapshotCollector(logger, client))
	prometheus.MustRegister(collector.NewVolumeCollector(logger, client))

	http.Handle(c.WebPath, promhttp.Handler())
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		_, _ = w.Write([]byte(`
			<title>DigitalOcean Exporter</title>

DigitalOcean Exporter

<a href="` + c.WebPath + `">Metrics

			`))
	})

	level.Info(logger).Log("msg", "listening", "addr", c.WebAddr)
	if err := http.ListenAndServe(c.WebAddr, nil); err != nil {
		level.Error(logger).Log("msg", "http listenandserve error", "err", err)
		os.Exit(1)
	}
}
<commit_msg>Add DEBUG env to change logger filter<commit_after>package main

import (
	"context"
	"net/http"
	"os"
	"runtime"
	"time"

	arg "github.com/alexflint/go-arg"
	"github.com/digitalocean/godo"
	"github.com/go-kit/kit/log"
	"github.com/go-kit/kit/log/level"
	"github.com/joho/godotenv"
	"github.com/metalmatze/digitalocean_exporter/collector"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"golang.org/x/oauth2"
)

var (
	// Version of digitalocean_exporter.
	Version string
	// Revision or Commit this binary was built from.
	Revision string
	// BuildDate this binary was built.
	BuildDate string
	// GoVersion running this binary.
	GoVersion = runtime.Version()
	// StartTime has the time this was started.
	StartTime = time.Now()
)

// Config gets its content from env and passes it on to different packages
type Config struct {
	Debug             bool   `arg:"env:DEBUG"`
	DigitalOceanToken string `arg:"env:DIGITALOCEAN_TOKEN"`
	WebAddr           string `arg:"env:WEB_ADDR"`
	WebPath           string `arg:"env:WEB_PATH"`
}

// Token returns a token or an error.
func (c Config) Token() (*oauth2.Token, error) {
	return &oauth2.Token{AccessToken: c.DigitalOceanToken}, nil
}

func main() {
	_ = godotenv.Load()

	c := Config{
		WebPath: "/metrics",
		WebAddr: ":9212",
	}
	arg.MustParse(&c)

	if c.DigitalOceanToken == "" {
		panic("DigitalOcean Token is required")
	}

	filterOption := level.AllowInfo()
	if c.Debug {
		filterOption = level.AllowDebug()
	}

	logger := log.NewLogfmtLogger(log.NewSyncWriter(os.Stderr))
	logger = level.NewFilter(logger, filterOption)
	logger = log.With(logger,
		"ts", log.DefaultTimestampUTC,
		"caller", log.DefaultCaller,
	)

	level.Info(logger).Log(
		"msg", "starting digitalocean_snapper",
		"version", Version,
		"revision", Revision,
		"buildDate", BuildDate,
		"goVersion", GoVersion,
	)

	oauthClient := oauth2.NewClient(context.TODO(), c)
	client := godo.NewClient(oauthClient)

	prometheus.MustRegister(collector.NewAccountCollector(logger, client))
	prometheus.MustRegister(collector.NewDropletCollector(logger, client))
	prometheus.MustRegister(collector.NewExporterCollector(logger, Version, Revision, BuildDate, GoVersion, StartTime))
	prometheus.MustRegister(collector.NewFloatingIPCollector(logger, client))
	prometheus.MustRegister(collector.NewImageCollector(logger, client))
	prometheus.MustRegister(collector.NewKeyCollector(logger, client))
	prometheus.MustRegister(collector.NewSnapshotCollector(logger, client))
	prometheus.MustRegister(collector.NewVolumeCollector(logger, client))

	http.Handle(c.WebPath, promhttp.Handler())
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		_, _ = w.Write([]byte(`
			<title>DigitalOcean Exporter</title>

DigitalOcean Exporter

<a href="` + c.WebPath + `">Metrics

			`))
	})

	level.Info(logger).Log("msg", "listening", "addr", c.WebAddr)
	if err := http.ListenAndServe(c.WebAddr, nil); err != nil {
		level.Error(logger).Log("msg", "http listenandserve error", "err", err)
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/gob"
	"flag"
	"fmt"
	"html/template"
	"log"
	"net/http"
	"os"
	"strings"
	"time"

	"github.com/DaemonNews/dnews/src"
	"github.com/gorilla/csrf"
	"github.com/gorilla/feeds"
	"github.com/gorilla/handlers"
	"github.com/gorilla/mux"
	"github.com/gorilla/sessions"
)

// TODO change this secret
var insecure bool
var cookieSecret string
var crsfSecret string
var templ *template.Template
var store *sessions.CookieStore

type response struct {
	Error string
	User  interface{}
	//Articles *dnews.Articles
	//Article  *dnews.Article
	Data interface{}
	CSRF map[string]interface{}
}

var funcMap = template.FuncMap{
	"formatDate": dnews.FormatDate,
	"printByte": func(b []byte) string {
		return string(b)
	},
	"joinTags": func(ts dnews.Tags) template.HTML {
		var s []string
		for _, t := range ts {

			s = append(s, fmt.Sprintf(`<a href="/tag/%s">%s</a>`, t.Name, t.Name))
		}
		return template.HTML(strings.Join(s, ", "))
	},
	"printHTML": func(b []byte) template.HTML {
		return template.HTML(string(b))
	},
}

func init() {
	var err error
	flag.BoolVar(&insecure, "i", false, "Insecure mode")
	flag.StringVar(&cookieSecret, "cookie", "something-very-secret", "Secret to use for cookie store")
	flag.StringVar(&crsfSecret, "crsf", "32-byte-long-auth-key", "Secret to use for cookie store")

	flag.Parse()

	store = sessions.NewCookieStore([]byte(cookieSecret))
	templ, err = template.New("dnews").Funcs(funcMap).ParseGlob("templates/*.html")
	if err != nil {
		log.Fatal(err)
	}

	gob.Register(&dnews.User{})
}

func renderTemplate(w http.ResponseWriter, r *http.Request, d *response, t string) {
	d.CSRF = map[string]interface{}{
		csrf.TemplateTag: csrf.TemplateField(r),
	}
	err := templ.ExecuteTemplate(w, t, d)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
}

func grabUser(w http.ResponseWriter, r *http.Request) (*response, error) {
	session, err := store.Get(r, "session-name")
	if err != nil {
		return nil, err
	}

	uVal := session.Values["user"]
	if _, ok := uVal.(*dnews.User); !ok {
		uVal = &dnews.User{}
		session.Values["user"] = &uVal
		session.Save(r, w)
	}

	var data = response{}
	data.User = &uVal
	return &data, nil
}

func main() {

	router := mux.NewRouter()
	router.PathPrefix("/public/").Handler(http.StripPrefix("/public/", http.FileServer(http.Dir("public"))))

	router.HandleFunc("/feeds", func(w http.ResponseWriter, r *http.Request) {
		data, err := grabUser(w, r)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		renderTemplate(w, r, data, "feeds.html")
	})
	router.HandleFunc("/ml", func(w http.ResponseWriter, r *http.Request) {
		data, err := grabUser(w, r)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		renderTemplate(w, r, data, "ml.html")
	})
	router.HandleFunc("/archives", func(w http.ResponseWriter, r *http.Request) {
		data, err := grabUser(w, r)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		renderTemplate(w, r, data, "archives.html")
	})
	router.HandleFunc("/search", func(w http.ResponseWriter, r *http.Request) {
		query := r.FormValue("search")
		data, err := grabUser(w, r)
		if err != nil {
			http.Error(w, fmt.Sprintf("Can't get user: %s", err.Error()), http.StatusInternalServerError)
			return
		}
		// TODO sanatize!
		a, err := dnews.SearchArticles(query, 100)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		data.Data = &a

		renderTemplate(w, r, data, "search_results.html")
	})

	router.HandleFunc("/feed/{type}", func(w http.ResponseWriter, r *http.Request) {
		vars := mux.Vars(r)
		feedType := vars["type"]
		now := time.Now()
		feed := &feeds.Feed{
			Title:       "Daemon.News",
			Link:        &feeds.Link{Href: "https://daemon.news"},
			Description: "*BSD News and Advocacy",
			Author:      &feeds.Author{Name: "The Daemon News Team", Email: "daemons@daemon.news"},
			Created:     now,
			Copyright:   "This work is copyright © Daemon.News",
		}

		a, err := dnews.GetNArticles(10)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		// TODO populate body?
		feed.Items = []*feeds.Item{}

		for _, article := range a {
			f := feeds.Item{}
			f.Title = article.Title
			f.Link = &feeds.Link{Href: fmt.Sprintf("http://daemon.news/article/%s", article.Slug)}
			f.Author = &feeds.Author{Name: article.Author.FName, Email: article.Author.Email}
			f.Created = article.Date

			feed.Items = append(feed.Items, &f)
		}

		switch feedType {
		case "atom":
			atom, err := feed.ToAtom()
			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
			fmt.Fprintf(w, atom)
		case "rss":
			rss, err := feed.ToRss()
			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
			fmt.Fprintf(w, rss)
		default:
			http.Error(w, "Invalid feed type!", http.StatusInternalServerError)
			return
		}

	})
	router.HandleFunc("/tag/{tag:[a-zA-Z0-9-]+}", func(w http.ResponseWriter, r *http.Request) {
		vars := mux.Vars(r)
		tag := vars["tag"]

		data, err := grabUser(w, r)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		articles, err := dnews.GetArticlesByTag(tag)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		data.Data = articles
		renderTemplate(w, r, data, "index.html")

	})
	router.HandleFunc("/article/{slug:[a-zA-Z0-9-]+}", func(w http.ResponseWriter, r *http.Request) {
		vars := mux.Vars(r)
		slug := vars["slug"]

		article, err := dnews.GetArticle(slug)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		data, err := grabUser(w, r)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		data.Data = article
		renderTemplate(w, r, data, "article.html")

	})
	router.HandleFunc("/article/raw/{slug:[a-zA-Z0-9-]+}", func(w http.ResponseWriter, r *http.Request) {
		vars := mux.Vars(r)
		slug := vars["slug"]

		article, err := dnews.GetRawArticle(slug)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		fmt.Fprintf(w, "%s", article.Body)
	})
	router.HandleFunc("/login/post", func(w http.ResponseWriter, r *http.Request) {
		session, err := store.Get(r, "session-name")
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		user := r.FormValue("user")
		passwd := r.FormValue("passwd")

		if user == "" && passwd == "" {
			http.Redirect(w, r, "/", http.StatusFound)
		} else {
			u, err := dnews.Auth(user, passwd)

			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}

			if u.Authed {
				session.Values["user"] = u
				session.Save(r, w)
				http.Redirect(w, r, "/", http.StatusFound)
			}
		}
	})
	router.HandleFunc("/login", func(w http.ResponseWriter, r *http.Request) {
		data, err := grabUser(w, r)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		renderTemplate(w, r, data, "login.html")
	})
	router.HandleFunc("/logout", func(w http.ResponseWriter, r *http.Request) {
		session, err := store.Get(r, "session-name")
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		session.Options = &sessions.Options{
			MaxAge: -1,
		}
		session.Save(r, w)
		http.Redirect(w, r, "/", http.StatusFound)

	})
	router.HandleFunc("/advocacy", func(w http.ResponseWriter, r *http.Request) {
		data, err := grabUser(w, r)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		bugs, err := dnews.GetBugs()
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		data.Data = &bugs

		renderTemplate(w, r, data, "advocacy.html")
	})
	router.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		data, err := grabUser(w, r)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		a, err := dnews.GetNArticles(10)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		data.Data = &a
		renderTemplate(w, r, data, "index.html")
	})

	loggedRouter := handlers.LoggingHandler(os.Stdout, router)

	// TODO change this secret
	if insecure {
		log.Fatal(http.ListenAndServe(":8080",
			csrf.Protect([]byte("32-byte-long-auth-key"),
				csrf.Secure(false))(loggedRouter)))
	} else {
		log.Fatal(http.ListenAndServe(":8080",
			csrf.Protect([]byte(crsfSecret))(loggedRouter)))

	}
}
<commit_msg>add -http<commit_after>package main

import (
	"encoding/gob"
	"flag"
	"fmt"
	"html/template"
	"log"
	"net/http"
	"os"
	"strings"
	"time"

	"github.com/DaemonNews/dnews/src"
	"github.com/gorilla/csrf"
	"github.com/gorilla/feeds"
	"github.com/gorilla/handlers"
	"github.com/gorilla/mux"
	"github.com/gorilla/sessions"
)

// TODO change this secret
var insecure bool
var cookieSecret string
var crsfSecret string
var templ *template.Template
var store *sessions.CookieStore
var listen string

type response struct {
	Error string
	User  interface{}
	//Articles *dnews.Articles
	//Article  *dnews.Article
	Data interface{}
	CSRF map[string]interface{}
}

var funcMap = template.FuncMap{
	"formatDate": dnews.FormatDate,
	"printByte": func(b []byte) string {
		return string(b)
	},
	"joinTags": func(ts dnews.Tags) template.HTML {
		var s []string
		for _, t := range ts {

			s = append(s, fmt.Sprintf(`<a href="/tag/%s">%s</a>`, t.Name, t.Name))
		}
		return template.HTML(strings.Join(s, ", "))
	},
	"printHTML": func(b []byte) template.HTML {
		return template.HTML(string(b))
	},
}

func init() {
	var err error
	flag.BoolVar(&insecure, "i", false, "Insecure mode")
	flag.StringVar(&cookieSecret, "cookie", "something-very-secret", "Secret to use for cookie store")
	flag.StringVar(&crsfSecret, "crsf", "32-byte-long-auth-key", "Secret to use for cookie store")
	flag.StringVar(&listen, "http", ":8080", "Listen on")

	flag.Parse()

	store = sessions.NewCookieStore([]byte(cookieSecret))
	templ, err = template.New("dnews").Funcs(funcMap).ParseGlob("templates/*.html")
	if err != nil {
		log.Fatal(err)
	}

	gob.Register(&dnews.User{})
}

func renderTemplate(w http.ResponseWriter, r *http.Request, d *response, t string) {
	d.CSRF = map[string]interface{}{
		csrf.TemplateTag: csrf.TemplateField(r),
	}
	err := templ.ExecuteTemplate(w, t, d)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
}

func grabUser(w http.ResponseWriter, r *http.Request) (*response, error) {
	session, err := store.Get(r, "session-name")
	if err != nil {
		return nil, err
	}

	uVal := session.Values["user"]
	if _, ok := uVal.(*dnews.User); !ok {
		uVal = &dnews.User{}
		session.Values["user"] = &uVal
		session.Save(r, w)
	}

	var data = response{}
	data.User = &uVal
	return &data, nil
}

func main() {

	router := mux.NewRouter()
	router.PathPrefix("/public/").Handler(http.StripPrefix("/public/", http.FileServer(http.Dir("public"))))

	router.HandleFunc("/feeds", func(w http.ResponseWriter, r *http.Request) {
		data, err := grabUser(w, r)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		renderTemplate(w, r, data, "feeds.html")
	})
	router.HandleFunc("/ml", func(w http.ResponseWriter, r *http.Request) {
		data, err := grabUser(w, r)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		renderTemplate(w, r, data, "ml.html")
	})
	router.HandleFunc("/archives", func(w http.ResponseWriter, r *http.Request) {
		data, err := grabUser(w, r)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		renderTemplate(w, r, data, "archives.html")
	})
	router.HandleFunc("/search", func(w http.ResponseWriter, r *http.Request) {
		query := r.FormValue("search")
		data, err := grabUser(w, r)
		if err != nil {
			http.Error(w, fmt.Sprintf("Can't get user: %s", err.Error()), http.StatusInternalServerError)
			return
		}
		// TODO sanatize!
		a, err := dnews.SearchArticles(query, 100)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		data.Data = &a

		renderTemplate(w, r, data, "search_results.html")
	})

	router.HandleFunc("/feed/{type}", func(w http.ResponseWriter, r *http.Request) {
		vars := mux.Vars(r)
		feedType := vars["type"]
		now := time.Now()
		feed := &feeds.Feed{
			Title:       "Daemon.News",
			Link:        &feeds.Link{Href: "https://daemon.news"},
			Description: "*BSD News and Advocacy",
			Author:      &feeds.Author{Name: "The Daemon News Team", Email: "daemons@daemon.news"},
			Created:     now,
			Copyright:   "This work is copyright © Daemon.News",
		}

		a, err := dnews.GetNArticles(10)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		// TODO populate body?
		feed.Items = []*feeds.Item{}

		for _, article := range a {
			f := feeds.Item{}
			f.Title = article.Title
			f.Link = &feeds.Link{Href: fmt.Sprintf("http://daemon.news/article/%s", article.Slug)}
			f.Author = &feeds.Author{Name: article.Author.FName, Email: article.Author.Email}
			f.Created = article.Date

			feed.Items = append(feed.Items, &f)
		}

		switch feedType {
		case "atom":
			atom, err := feed.ToAtom()
			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
			fmt.Fprintf(w, atom)
		case "rss":
			rss, err := feed.ToRss()
			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
			fmt.Fprintf(w, rss)
		default:
			http.Error(w, "Invalid feed type!", http.StatusInternalServerError)
			return
		}

	})
	router.HandleFunc("/tag/{tag:[a-zA-Z0-9-]+}", func(w http.ResponseWriter, r *http.Request) {
		vars := mux.Vars(r)
		tag := vars["tag"]

		data, err := grabUser(w, r)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		articles, err := dnews.GetArticlesByTag(tag)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		data.Data = articles
		renderTemplate(w, r, data, "index.html")

	})
	router.HandleFunc("/article/{slug:[a-zA-Z0-9-]+}", func(w http.ResponseWriter, r *http.Request) {
		vars := mux.Vars(r)
		slug := vars["slug"]

		article, err := dnews.GetArticle(slug)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		data, err := grabUser(w, r)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		data.Data = article
		renderTemplate(w, r, data, "article.html")

	})
	router.HandleFunc("/article/raw/{slug:[a-zA-Z0-9-]+}", func(w http.ResponseWriter, r *http.Request) {
		vars := mux.Vars(r)
		slug := vars["slug"]

		article, err := dnews.GetRawArticle(slug)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		fmt.Fprintf(w, "%s", article.Body)
	})
	router.HandleFunc("/login/post", func(w http.ResponseWriter, r *http.Request) {
		session, err := store.Get(r, "session-name")
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		user := r.FormValue("user")
		passwd := r.FormValue("passwd")

		if user == "" && passwd == "" {
			http.Redirect(w, r, "/", http.StatusFound)
		} else {
			u, err := dnews.Auth(user, passwd)

			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}

			if u.Authed {
				session.Values["user"] = u
				session.Save(r, w)
				http.Redirect(w, r, "/", http.StatusFound)
			}
		}
	})
	router.HandleFunc("/login", func(w http.ResponseWriter, r *http.Request) {
		data, err := grabUser(w, r)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		renderTemplate(w, r, data, "login.html")
	})
	router.HandleFunc("/logout", func(w http.ResponseWriter, r *http.Request) {
		session, err := store.Get(r, "session-name")
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		session.Options = &sessions.Options{
			MaxAge: -1,
		}
		session.Save(r, w)
		http.Redirect(w, r, "/", http.StatusFound)

	})
	router.HandleFunc("/advocacy", func(w http.ResponseWriter, r *http.Request) {
		data, err := grabUser(w, r)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		bugs, err := dnews.GetBugs()
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		data.Data = &bugs

		renderTemplate(w, r, data, "advocacy.html")
	})
	router.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		data, err := grabUser(w, r)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		a, err := dnews.GetNArticles(10)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		data.Data = &a
		renderTemplate(w, r, data, "index.html")
	})

	loggedRouter := handlers.LoggingHandler(os.Stdout, router)

	// TODO change this secret
	if insecure {
		log.Fatal(http.ListenAndServe(listen,
			csrf.Protect([]byte("32-byte-long-auth-key"),
				csrf.Secure(false))(loggedRouter)))
	} else {
		log.Fatal(http.ListenAndServe(listen,
			csrf.Protect([]byte(crsfSecret))(loggedRouter)))

	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"path/filepath"
	"strings"

	adrianConfig "Adrian2.0/config"
	adrianFonts "Adrian2.0/fonts"
	adrianServer "Adrian2.0/server"

	"github.com/labstack/echo"
)

func main() {

	log.Println("Starting Adrian 2.0")
	log.Println("Loading adrian.yaml")
	config := adrianConfig.LoadConfig("./adrian.yaml")
	log.Println("Initializing web server")
	e := adrianServer.Instantiate(config)
	log.Println("Loading fonts and starting watchers")
	for _, folder := range config.Global.Directories {
		adrianFonts.FindFonts(folder, config)
		adrianFonts.InstantiateWatcher(folder, config)
	}
	log.Println("Defining paths")

	e.GET("/css/", func(c echo.Context) error {
		c.Response().Header().Set(echo.HeaderContentType, "text/css")
		fontFilenames := strings.Split(c.QueryParam("family"), "|")
		var fontsCSS string
		for _, fontFilename := range fontFilenames {
			fontData, err := adrianFonts.GetFont(fontFilename)
			if err != nil {
				return adrianServer.Return404(c)
			}
			fontsCSS = fontsCSS + "\n" + fontData.CSS

			pusher, ok := c.Response().Writer.(http.Pusher)
			if ok {
				// Attempt HTTP/2 Server Push with native support
				if err = pusher.Push(fmt.Sprintf("/font/%s.%s", fontData.UniqueID, fontData.Type), nil); err != nil {
					log.Fatal("Could not http/2 server push " + fontData.UniqueID + " " + fontData.Type)
				}
				log.Println("Pushing font")
			} else {
				// Send a Link: header in case an upstream web server supports HTTP/2 server push
				c.Response().Header().Set("Link", fmt.Sprintf("/font/%s.%s>; rel=preload; as=font", fontData.UniqueID, fontData.Type))
			}
		}
		return c.String(http.StatusOK, fontsCSS)
	})

	e.GET("/font/:filename", func(c echo.Context) error {
		switch filepath.Ext(c.Param("filename")) {
		case ".ttf":
			return outputFont(c, "font/ttf")
		case ".woff":
			return outputFont(c, "font/woff")
		case ".woff2":
			return outputFont(c, "font/woff2")
		case ".otf":
			return outputFont(c, "font/otf")
		}

		return adrianServer.Return404(c)

	})

	log.Printf("Listening on port %d", config.Global.Port)
	e.Logger.Fatal(e.Start(fmt.Sprintf(":%d", config.Global.Port)))
}

// Basename gets the base filename (minus the last extension)
func basename(s string) string {
	n := strings.LastIndexByte(s, '.')
	if n >= 0 {
		return s[:n]
	}
	return s
}

func outputFont(c echo.Context, mimeType string) error {
	fontData, err := adrianFonts.GetFontByUniqueID(basename(c.Param("filename")))
	if err != nil {
		return adrianServer.Return404(c)
	}
	fontBinary, err := ioutil.ReadFile(fontData.Path) // just pass the file name
	if err != nil {
		log.Fatal("Can't read font file " + fontData.FileName)
	}
	return c.Blob(http.StatusOK, mimeType, fontBinary)

}
<commit_msg>Better log message<commit_after>package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"path/filepath"
	"strings"

	adrianConfig "Adrian2.0/config"
	adrianFonts "Adrian2.0/fonts"
	adrianServer "Adrian2.0/server"

	"github.com/labstack/echo"
)

func main() {

	log.Println("Starting Adrian 2.0")
	log.Println("Loading adrian.yaml")
	config := adrianConfig.LoadConfig("./adrian.yaml")
	log.Println("Initializing web server")
	e := adrianServer.Instantiate(config)
	log.Println("Loading fonts and starting watchers")
	for _, folder := range config.Global.Directories {
		adrianFonts.FindFonts(folder, config)
		adrianFonts.InstantiateWatcher(folder, config)
	}
	log.Println("Defining paths")

	e.GET("/css/", func(c echo.Context) error {
		c.Response().Header().Set(echo.HeaderContentType, "text/css")
		fontFilenames := strings.Split(c.QueryParam("family"), "|")
		var fontsCSS string
		for _, fontFilename := range fontFilenames {
			fontData, err := adrianFonts.GetFont(fontFilename)
			if err != nil {
				return adrianServer.Return404(c)
			}
			fontsCSS = fontsCSS + "\n" + fontData.CSS

			pusher, ok := c.Response().Writer.(http.Pusher)
			if ok {
				// Attempt HTTP/2 Server Push with native support
				if err = pusher.Push(fmt.Sprintf("/font/%s.%s", fontData.UniqueID, fontData.Type), nil); err != nil {
					log.Fatal("Could not http/2 server push " + fontData.UniqueID + " " + fontData.Type)
				}
				log.Println("Pushing font " + fontData.UniqueID + " " + fontData.Type)
			} else {
				// Send a Link: header in case an upstream web server supports HTTP/2 server push
				c.Response().Header().Set("Link", fmt.Sprintf("/font/%s.%s>; rel=preload; as=font", fontData.UniqueID, fontData.Type))
			}
		}
		return c.String(http.StatusOK, fontsCSS)
	})

	e.GET("/font/:filename", func(c echo.Context) error {
		switch filepath.Ext(c.Param("filename")) {
		case ".ttf":
			return outputFont(c, "font/ttf")
		case ".woff":
			return outputFont(c, "font/woff")
		case ".woff2":
			return outputFont(c, "font/woff2")
		case ".otf":
			return outputFont(c, "font/otf")
		}

		return adrianServer.Return404(c)

	})

	log.Printf("Listening on port %d", config.Global.Port)
	e.Logger.Fatal(e.Start(fmt.Sprintf(":%d", config.Global.Port)))
}

// Basename gets the base filename (minus the last extension)
func basename(s string) string {
	n := strings.LastIndexByte(s, '.')
	if n >= 0 {
		return s[:n]
	}
	return s
}

func outputFont(c echo.Context, mimeType string) error {
	fontData, err := adrianFonts.GetFontByUniqueID(basename(c.Param("filename")))
	if err != nil {
		return adrianServer.Return404(c)
	}
	fontBinary, err := ioutil.ReadFile(fontData.Path) // just pass the file name
	if err != nil {
		log.Fatal("Can't read font file " + fontData.FileName)
	}
	return c.Blob(http.StatusOK, mimeType, fontBinary)

}
<|endoftext|>


<commit_before>// Copyright (c) 2015 Jan Broer. All rights reserved.
// Use of this source code is governed by The MIT License (MIT) that can be
// found in the LICENSE file.

package main // import "github.com/janeczku/go-dnsmasq"

import (
	"fmt"
	"log/syslog"
	"net"
	"os"
	"os/signal"
	"runtime"
	"strconv"
	"strings"
	"syscall"
	"time"

	log "github.com/Sirupsen/logrus"
	logrus_syslog "github.com/Sirupsen/logrus/hooks/syslog"
	"github.com/codegangsta/cli"
	"github.com/miekg/dns"

	"github.com/janeczku/go-dnsmasq/hostsfile"
	"github.com/janeczku/go-dnsmasq/resolvconf"
	"github.com/janeczku/go-dnsmasq/server"
	"github.com/janeczku/go-dnsmasq/stats"
)

// set at build time
var Version = "dev"

var (
	nameservers   = []string{}
	searchDomains = []string{}
	hostPort      = ""
	listen        = ""
)

var exitErr error

func init() {
	log.SetOutput(os.Stdout)
}

func main() {
	app := cli.NewApp()
	app.Name = "go-dnsmasq"
	app.Usage = "Lightweight caching DNS server and forwarder\n   Website: http://github.com/janeczku/go-dnsmasq"
	app.UsageText = "go-dnsmasq [global options]"
	app.Version = Version
	app.Author, app.Email = "", ""
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:   "listen, l",
			Value:  "127.0.0.1:53",
			Usage:  "Listen on this `address` <host[:port]>",
			EnvVar: "DNSMASQ_LISTEN",
		},
		cli.BoolFlag{
			Name:   "default-resolver, d",
			Usage:  "Update /etc/resolv.conf with the address of go-dnsmasq as nameserver",
			EnvVar: "DNSMASQ_DEFAULT",
		},
		cli.StringFlag{
			Name:   "nameservers, n",
			Value:  "",
			Usage:  "Comma delimited list of `nameservers` <host[:port][,host[:port]]> (supersedes resolv.conf)",
			EnvVar: "DNSMASQ_SERVERS",
		},
		cli.StringSliceFlag{
			Name:   "stubzones, z",
			Usage:  "Use different nameservers for given domains <domain[,domain]/host[:port][,host[:port]]>",
			EnvVar: "DNSMASQ_STUB",
		},
		cli.StringFlag{
			Name:   "hostsfile, f",
			Value:  "",
			Usage:  "Path to a hosts `file` (e.g. /etc/hosts)",
			EnvVar: "DNSMASQ_HOSTSFILE",
		},
		cli.IntFlag{
			Name:   "hostsfile-poll, p",
			Value:  0,
			Usage:  "How frequently to poll hosts file (`seconds`, '0' to disable)",
			EnvVar: "DNSMASQ_POLL",
		},
		cli.StringFlag{
			Name:   "search-domains, s",
			Value:  "",
			Usage:  "List of search domains <domain[,domain]> (supersedes resolv.conf)",
			EnvVar: "DNSMASQ_SEARCH_DOMAINS,DNSMASQ_SEARCH,", // deprecated DNSMASQ_SEARCH
		},
		cli.BoolFlag{ // deprecated
			Name:   "append-search-domains, a",
			Usage:  "Resolve queries using search domains",
			EnvVar: "DNSMASQ_APPEND",
			Hidden: true,
		},
		cli.BoolFlag{
			Name:   "enable-search, search",
			Usage:  "Qualify names with search domains to resolve queries",
			EnvVar: "DNSMASQ_ENABLE_SEARCH",
		},
		cli.IntFlag{
			Name:   "rcache, r",
			Value:  0,
			Usage:  "Response cache `capacity` ('0' disables caching)",
			EnvVar: "DNSMASQ_RCACHE",
		},
		cli.IntFlag{
			Name:   "rcache-ttl",
			Value:  60,
			Usage:  "TTL in `seconds` for response cache entries",
			EnvVar: "DNSMASQ_RCACHE_TTL",
		},
		cli.BoolFlag{
			Name:   "no-rec",
			Usage:  "Disable recursion",
			EnvVar: "DNSMASQ_NOREC",
		},
		cli.IntFlag{
			Name:   "fwd-ndots",
			Value:  0,
			Usage:  "Number of `dots` a name must have before the query is forwarded",
			EnvVar: "DNSMASQ_FWD_NDOTS",
		},
		cli.IntFlag{
			Name:   "ndots",
			Value:  1,
			Usage:  "Number of `dots` a name must have before doing an initial absolute query (supersedes resolv.conf)",
			EnvVar: "DNSMASQ_NDOTS",
		},
		cli.BoolFlag{
			Name:   "round-robin",
			Usage:  "Enable round robin of A/AAAA records",
			EnvVar: "DNSMASQ_RR",
		},
		cli.BoolFlag{
			Name:   "systemd",
			Usage:  "Bind to socket activated by Systemd (supersedes '--listen')",
			EnvVar: "DNSMASQ_SYSTEMD",
		},
		cli.BoolFlag{
			Name:   "verbose",
			Usage:  "Enable verbose logging",
			EnvVar: "DNSMASQ_VERBOSE",
		},
		cli.BoolFlag{
			Name:   "syslog",
			Usage:  "Enable syslog logging",
			EnvVar: "DNSMASQ_SYSLOG",
		},
		cli.BoolFlag{
			Name:   "multithreading",
			Usage:  "Enable multithreading (experimental)",
			EnvVar: "DNSMASQ_MULTITHREADING",
		},
	}
	app.Action = func(c *cli.Context) error {
		exitReason := make(chan error)
		go func() {
			c := make(chan os.Signal, 1)
			signal.Notify(c, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
			sig := <-c
			log.Infoln("Application exit requested by signal:", sig)
			exitReason <- nil
		}()

		var enableSearch bool
		if c.IsSet("append-search-domains") {
			log.Info("The flag '--append-search-domains' is deprecated. Please use '--enable-search' or '-search' instead.")
			enableSearch = c.Bool("append-search-domains")
		} else {
			enableSearch = c.Bool("enable-search")
		}

		if c.Bool("multithreading") {
			runtime.GOMAXPROCS(runtime.NumCPU() + 1)
		}

		if c.Bool("verbose") {
			log.SetLevel(log.DebugLevel)
		}

		if c.Bool("syslog") {
			log.SetFormatter(&log.TextFormatter{DisableTimestamp: true, DisableColors: true})
			hook, err := logrus_syslog.NewSyslogHook("", "", syslog.LOG_DAEMON|syslog.LOG_INFO, "go-dnsmasq")
			if err != nil {
				log.Error("Unable to connect to local syslog daemon")
			} else {
				log.AddHook(hook)
			}
		} else {
			log.SetFormatter(&log.TextFormatter{})
		}

		if ns := c.String("nameservers"); ns != "" {
			for _, hostPort := range strings.Split(ns, ",") {
				hostPort = strings.TrimSpace(hostPort)
				if strings.HasSuffix(hostPort, "]") {
					hostPort += ":53"
				} else if !strings.Contains(hostPort, ":") {
					hostPort += ":53"
				}
				if err := validateHostPort(hostPort); err != nil {
					log.Fatalf("Nameserver is invalid: %s", err)
				}

				nameservers = append(nameservers, hostPort)
			}
		}

		if sd := c.String("search-domains"); sd != "" {
			for _, domain := range strings.Split(sd, ",") {
				if dns.CountLabel(domain) < 2 {
					log.Fatalf("Search domain must have at least one dot in name: %s", domain)
				}
				domain = strings.TrimSpace(domain)
				domain = dns.Fqdn(strings.ToLower(domain))
				searchDomains = append(searchDomains, domain)
			}
		}

		listen = c.String("listen")
		if strings.HasSuffix(listen, "]") {
			listen += ":53"
		} else if !strings.Contains(listen, ":") {
			listen += ":53"
		}

		if err := validateHostPort(listen); err != nil {
			log.Fatalf("Listen address is invalid: %s", err)
		}

		config := &server.Config{
			DnsAddr:         listen,
			DefaultResolver: c.Bool("default-resolver"),
			Nameservers:     nameservers,
			Systemd:         c.Bool("systemd"),
			SearchDomains:   searchDomains,
			EnableSearch:    enableSearch,
			Hostsfile:       c.String("hostsfile"),
			PollInterval:    c.Int("hostsfile-poll"),
			RoundRobin:      c.Bool("round-robin"),
			NoRec:           c.Bool("no-rec"),
			FwdNdots:        c.Int("fwd-ndots"),
			Ndots:           c.Int("ndots"),
			ReadTimeout:     2 * time.Second,
			RCache:          c.Int("rcache"),
			RCacheTtl:       c.Int("rcache-ttl"),
			Verbose:         c.Bool("verbose"),
		}

		if err := server.ResolvConf(config, c); err != nil {
			if !os.IsNotExist(err) {
				log.Warnf("Error parsing resolv.conf: %s", err.Error())
			}
		}

		if err := server.CheckConfig(config); err != nil {
			log.Fatal(err.Error())
		}

		if stubzones := c.StringSlice("stubzones"); len(stubzones) > 0 {
			stubmap := make(map[string][]string)
			for _, stubzone := range stubzones {
				segments := strings.Split(stubzone, "/")
				if len(segments) != 2 || len(segments[0]) == 0 || len(segments[1]) == 0 {
					log.Fatalf("The --stubzones argument is invalid")
				}

				hosts := strings.Split(segments[1], ",")
				for _, hostPort := range hosts {
					hostPort = strings.TrimSpace(hostPort)
					if strings.HasSuffix(hostPort, "]") {
						hostPort += ":53"
					} else if !strings.Contains(hostPort, ":") {
						hostPort += ":53"
					}

					if err := validateHostPort(hostPort); err != nil {
						log.Fatalf("This stubzones server address invalid: %s", err)
					}

					for _, sdomain := range strings.Split(segments[0], ",") {
						if dns.CountLabel(sdomain) < 1 {
							log.Fatalf("This stubzones domain is not a FQDN: %s", sdomain)
						}
						sdomain = strings.TrimSpace(sdomain)
						sdomain = dns.Fqdn(sdomain)
						stubmap[sdomain] = append(stubmap[sdomain], hostPort)
					}
				}
			}
			config.Stub = &stubmap
		}

		log.Infof("Starting go-dnsmasq server %s", Version)
		log.Infof("Nameservers: %v", config.Nameservers)
		if config.EnableSearch {
			log.Infof("Search domains: %v", config.SearchDomains)
		}

		hf, err := hosts.NewHostsfile(config.Hostsfile, &hosts.Config{
			Poll:    config.PollInterval,
			Verbose: config.Verbose,
		})
		if err != nil {
			log.Fatalf("Error loading hostsfile: %s", err)
		}

		s := server.New(hf, config, Version)

		defer s.Stop()

		stats.Collect()

		if config.DefaultResolver {
			address, _, _ := net.SplitHostPort(config.DnsAddr)
			err := resolvconf.StoreAddress(address)
			if err != nil {
				log.Warnf("Failed to register as default nameserver: %s", err)
			}
			defer resolvconf.Clean()
		}

		go func() {
			if err := s.Run(); err != nil {
				exitReason <- err
			}
		}()

		exitErr = <-exitReason
		if exitErr != nil {
			log.Fatalf("Server error: %s", err)
		}

		return nil
	}

	app.Run(os.Args)
}

func validateHostPort(hostPort string) error {
	host, port, err := net.SplitHostPort(hostPort)
	if err != nil {
		return err
	}
	if ip := net.ParseIP(host); ip == nil {
		return fmt.Errorf("Bad IP address: %s", host)
	}

	if p, _ := strconv.Atoi(port); p < 1 || p > 65535 {
		return fmt.Errorf("Bad port number %s", port)
	}
	return nil
}
<commit_msg>Fix some error strings<commit_after>// Copyright (c) 2015 Jan Broer. All rights reserved.
// Use of this source code is governed by The MIT License (MIT) that can be
// found in the LICENSE file.

package main // import "github.com/janeczku/go-dnsmasq"

import (
	"fmt"
	"log/syslog"
	"net"
	"os"
	"os/signal"
	"runtime"
	"strconv"
	"strings"
	"syscall"
	"time"

	log "github.com/Sirupsen/logrus"
	logrus_syslog "github.com/Sirupsen/logrus/hooks/syslog"
	"github.com/codegangsta/cli"
	"github.com/miekg/dns"

	"github.com/janeczku/go-dnsmasq/hostsfile"
	"github.com/janeczku/go-dnsmasq/resolvconf"
	"github.com/janeczku/go-dnsmasq/server"
	"github.com/janeczku/go-dnsmasq/stats"
)

// set at build time
var Version = "dev"

var (
	nameservers   = []string{}
	searchDomains = []string{}
	hostPort      = ""
	listen        = ""
)

var exitErr error

func init() {
	log.SetOutput(os.Stdout)
}

func main() {
	app := cli.NewApp()
	app.Name = "go-dnsmasq"
	app.Usage = "Lightweight caching DNS server and forwarder\n   Website: http://github.com/janeczku/go-dnsmasq"
	app.UsageText = "go-dnsmasq [global options]"
	app.Version = Version
	app.Author, app.Email = "", ""
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:   "listen, l",
			Value:  "127.0.0.1:53",
			Usage:  "Listen on this `address` <host[:port]>",
			EnvVar: "DNSMASQ_LISTEN",
		},
		cli.BoolFlag{
			Name:   "default-resolver, d",
			Usage:  "Update /etc/resolv.conf with the address of go-dnsmasq as nameserver",
			EnvVar: "DNSMASQ_DEFAULT",
		},
		cli.StringFlag{
			Name:   "nameservers, n",
			Value:  "",
			Usage:  "Comma delimited list of `nameservers` <host[:port][,host[:port]]> (supersedes resolv.conf)",
			EnvVar: "DNSMASQ_SERVERS",
		},
		cli.StringSliceFlag{
			Name:   "stubzones, z",
			Usage:  "Use different nameservers for given domains <domain[,domain]/host[:port][,host[:port]]>",
			EnvVar: "DNSMASQ_STUB",
		},
		cli.StringFlag{
			Name:   "hostsfile, f",
			Value:  "",
			Usage:  "Path to a hosts `file` (e.g. /etc/hosts)",
			EnvVar: "DNSMASQ_HOSTSFILE",
		},
		cli.IntFlag{
			Name:   "hostsfile-poll, p",
			Value:  0,
			Usage:  "How frequently to poll hosts file (`seconds`, '0' to disable)",
			EnvVar: "DNSMASQ_POLL",
		},
		cli.StringFlag{
			Name:   "search-domains, s",
			Value:  "",
			Usage:  "List of search domains <domain[,domain]> (supersedes resolv.conf)",
			EnvVar: "DNSMASQ_SEARCH_DOMAINS,DNSMASQ_SEARCH,", // deprecated DNSMASQ_SEARCH
		},
		cli.BoolFlag{ // deprecated
			Name:   "append-search-domains, a",
			Usage:  "Resolve queries using search domains",
			EnvVar: "DNSMASQ_APPEND",
			Hidden: true,
		},
		cli.BoolFlag{
			Name:   "enable-search, search",
			Usage:  "Qualify names with search domains to resolve queries",
			EnvVar: "DNSMASQ_ENABLE_SEARCH",
		},
		cli.IntFlag{
			Name:   "rcache, r",
			Value:  0,
			Usage:  "Response cache `capacity` ('0' disables caching)",
			EnvVar: "DNSMASQ_RCACHE",
		},
		cli.IntFlag{
			Name:   "rcache-ttl",
			Value:  60,
			Usage:  "TTL in `seconds` for response cache entries",
			EnvVar: "DNSMASQ_RCACHE_TTL",
		},
		cli.BoolFlag{
			Name:   "no-rec",
			Usage:  "Disable recursion",
			EnvVar: "DNSMASQ_NOREC",
		},
		cli.IntFlag{
			Name:   "fwd-ndots",
			Value:  0,
			Usage:  "Number of `dots` a name must have before the query is forwarded",
			EnvVar: "DNSMASQ_FWD_NDOTS",
		},
		cli.IntFlag{
			Name:   "ndots",
			Value:  1,
			Usage:  "Number of `dots` a name must have before doing an initial absolute query (supersedes resolv.conf)",
			EnvVar: "DNSMASQ_NDOTS",
		},
		cli.BoolFlag{
			Name:   "round-robin",
			Usage:  "Enable round robin of A/AAAA records",
			EnvVar: "DNSMASQ_RR",
		},
		cli.BoolFlag{
			Name:   "systemd",
			Usage:  "Bind to socket activated by Systemd (supersedes '--listen')",
			EnvVar: "DNSMASQ_SYSTEMD",
		},
		cli.BoolFlag{
			Name:   "verbose",
			Usage:  "Enable verbose logging",
			EnvVar: "DNSMASQ_VERBOSE",
		},
		cli.BoolFlag{
			Name:   "syslog",
			Usage:  "Enable syslog logging",
			EnvVar: "DNSMASQ_SYSLOG",
		},
		cli.BoolFlag{
			Name:   "multithreading",
			Usage:  "Enable multithreading (experimental)",
			EnvVar: "DNSMASQ_MULTITHREADING",
		},
	}
	app.Action = func(c *cli.Context) error {
		exitReason := make(chan error)
		go func() {
			c := make(chan os.Signal, 1)
			signal.Notify(c, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
			sig := <-c
			log.Infoln("Application exit requested by signal:", sig)
			exitReason <- nil
		}()

		var enableSearch bool
		if c.IsSet("append-search-domains") {
			log.Info("The flag '--append-search-domains' is deprecated. Please use '--enable-search' or '-search' instead.")
			enableSearch = c.Bool("append-search-domains")
		} else {
			enableSearch = c.Bool("enable-search")
		}

		if c.Bool("multithreading") {
			runtime.GOMAXPROCS(runtime.NumCPU() + 1)
		}

		if c.Bool("verbose") {
			log.SetLevel(log.DebugLevel)
		}

		if c.Bool("syslog") {
			log.SetFormatter(&log.TextFormatter{DisableTimestamp: true, DisableColors: true})
			hook, err := logrus_syslog.NewSyslogHook("", "", syslog.LOG_DAEMON|syslog.LOG_INFO, "go-dnsmasq")
			if err != nil {
				log.Error("Unable to connect to local syslog daemon")
			} else {
				log.AddHook(hook)
			}
		} else {
			log.SetFormatter(&log.TextFormatter{})
		}

		if ns := c.String("nameservers"); ns != "" {
			for _, hostPort := range strings.Split(ns, ",") {
				hostPort = strings.TrimSpace(hostPort)
				if strings.HasSuffix(hostPort, "]") {
					hostPort += ":53"
				} else if !strings.Contains(hostPort, ":") {
					hostPort += ":53"
				}
				if err := validateHostPort(hostPort); err != nil {
					log.Fatalf("Nameserver is invalid: %s", err)
				}

				nameservers = append(nameservers, hostPort)
			}
		}

		if sd := c.String("search-domains"); sd != "" {
			for _, domain := range strings.Split(sd, ",") {
				if dns.CountLabel(domain) < 2 {
					log.Fatalf("Search domain must have at least one dot in name: %s", domain)
				}
				domain = strings.TrimSpace(domain)
				domain = dns.Fqdn(strings.ToLower(domain))
				searchDomains = append(searchDomains, domain)
			}
		}

		listen = c.String("listen")
		if strings.HasSuffix(listen, "]") {
			listen += ":53"
		} else if !strings.Contains(listen, ":") {
			listen += ":53"
		}

		if err := validateHostPort(listen); err != nil {
			log.Fatalf("Listen address is invalid: %s", err)
		}

		config := &server.Config{
			DnsAddr:         listen,
			DefaultResolver: c.Bool("default-resolver"),
			Nameservers:     nameservers,
			Systemd:         c.Bool("systemd"),
			SearchDomains:   searchDomains,
			EnableSearch:    enableSearch,
			Hostsfile:       c.String("hostsfile"),
			PollInterval:    c.Int("hostsfile-poll"),
			RoundRobin:      c.Bool("round-robin"),
			NoRec:           c.Bool("no-rec"),
			FwdNdots:        c.Int("fwd-ndots"),
			Ndots:           c.Int("ndots"),
			ReadTimeout:     2 * time.Second,
			RCache:          c.Int("rcache"),
			RCacheTtl:       c.Int("rcache-ttl"),
			Verbose:         c.Bool("verbose"),
		}

		if err := server.ResolvConf(config, c); err != nil {
			if !os.IsNotExist(err) {
				log.Warnf("Error parsing resolv.conf: %s", err.Error())
			}
		}

		if err := server.CheckConfig(config); err != nil {
			log.Fatal(err.Error())
		}

		if stubzones := c.StringSlice("stubzones"); len(stubzones) > 0 {
			stubmap := make(map[string][]string)
			for _, stubzone := range stubzones {
				segments := strings.Split(stubzone, "/")
				if len(segments) != 2 || len(segments[0]) == 0 || len(segments[1]) == 0 {
					log.Fatalf("Invalid value for --stubzones")
				}

				hosts := strings.Split(segments[1], ",")
				for _, hostPort := range hosts {
					hostPort = strings.TrimSpace(hostPort)
					if strings.HasSuffix(hostPort, "]") {
						hostPort += ":53"
					} else if !strings.Contains(hostPort, ":") {
						hostPort += ":53"
					}

					if err := validateHostPort(hostPort); err != nil {
						log.Fatalf("Stubzone server address is invalid: %s", err)
					}

					for _, sdomain := range strings.Split(segments[0], ",") {
						if dns.CountLabel(sdomain) < 1 {
							log.Fatalf("Stubzone domain is not a fully-qualified domain name: %s", sdomain)
						}
						sdomain = strings.TrimSpace(sdomain)
						sdomain = dns.Fqdn(sdomain)
						stubmap[sdomain] = append(stubmap[sdomain], hostPort)
					}
				}
			}
			config.Stub = &stubmap
		}

		log.Infof("Starting go-dnsmasq server %s", Version)
		log.Infof("Nameservers: %v", config.Nameservers)
		if config.EnableSearch {
			log.Infof("Search domains: %v", config.SearchDomains)
		}

		hf, err := hosts.NewHostsfile(config.Hostsfile, &hosts.Config{
			Poll:    config.PollInterval,
			Verbose: config.Verbose,
		})
		if err != nil {
			log.Fatalf("Error loading hostsfile: %s", err)
		}

		s := server.New(hf, config, Version)

		defer s.Stop()

		stats.Collect()

		if config.DefaultResolver {
			address, _, _ := net.SplitHostPort(config.DnsAddr)
			err := resolvconf.StoreAddress(address)
			if err != nil {
				log.Warnf("Failed to register as default nameserver: %s", err)
			}
			defer resolvconf.Clean()
		}

		go func() {
			if err := s.Run(); err != nil {
				exitReason <- err
			}
		}()

		exitErr = <-exitReason
		if exitErr != nil {
			log.Fatalf("Server error: %s", err)
		}

		return nil
	}

	app.Run(os.Args)
}

func validateHostPort(hostPort string) error {
	host, port, err := net.SplitHostPort(hostPort)
	if err != nil {
		return err
	}
	if ip := net.ParseIP(host); ip == nil {
		return fmt.Errorf("Bad IP address: %s", host)
	}

	if p, _ := strconv.Atoi(port); p < 1 || p > 65535 {
		return fmt.Errorf("Bad port number %s", port)
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/bmizerany/noeq.go"
	"github.com/bmizerany/pat"
	"github.com/mrb/riakpbc"

	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
)

var (
	riakc *riakpbc.Conn
	noeqc *noeq.Client
	err   error
)

func GetId(w http.ResponseWriter, req *http.Request) {
	id, _ := noeqc.GenOne()
	stringId := fmt.Sprintf("%d", id)

	log.Print(" [GET] {id: ", stringId, "}")

	io.WriteString(w, stringId)
}

func PostData(w http.ResponseWriter, req *http.Request) {
	body, _ := ioutil.ReadAll(req.Body)
	id, _ := noeqc.GenOne()

	stringId := fmt.Sprintf("%d", id)
	stringBody := fmt.Sprintf("%s", body)

	_, err := riakc.StoreObject("data", stringId, stringBody)

	if err != nil {
		log.Print(err)
	}

	log.Print("[POST] {id: ", stringId, "}, {body: ", stringBody, "}")

	io.WriteString(w, stringId)
}

func GetData(w http.ResponseWriter, req *http.Request) {
	stringId := req.URL.Query().Get(":id")

	data, err := riakc.FetchObject("data", stringId)
	if err != nil {
		log.Print(err)
	}

	log.Print(" [GET] ", string(data))

	io.WriteString(w, string(data))
}

func main() {
	riakc, err = riakpbc.New("127.0.0.1:8087", 1e8, 1e8)
	if err != nil {
		log.Print(err)
		return
	}

	noeqc, err = noeq.New("", "127.0.0.1:4444")
	if err != nil {
		log.Print(err)
		return
	}

	err = riakc.Dial()
	if err != nil {
		log.Print(err)
		return
	}

	m := pat.New()
	m.Get("/id/new", http.HandlerFunc(GetId))
	m.Post("/data", http.HandlerFunc(PostData))
	m.Get("/data/:id", http.HandlerFunc(GetData))

	http.Handle("/", m)

	log.Print("[INFO] ...starting your shoebox....")

	err = http.ListenAndServe(":12345", nil)
	if err != nil {
		log.Fatal("ListenAndServe: ", err)
	}
}
<commit_msg>Implement HTTP Status errors<commit_after>package main

import (
	"github.com/bmizerany/noeq.go"
	"github.com/bmizerany/pat"
	"github.com/mrb/riakpbc"

	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
)

var (
	riakc *riakpbc.Conn
	noeqc *noeq.Client
	err   error
)

func GetId(w http.ResponseWriter, req *http.Request) {
	id, err := noeqc.GenOne()
	if err != nil {
		log.Print(" [GET] 500 Server Error")
		http.Error(w, "Server Error", 500)
		return
	}
	stringId := fmt.Sprintf("%d", id)

	log.Print(" [GET] {id: ", stringId, "}")

	io.WriteString(w, stringId)
}

func PostData(w http.ResponseWriter, req *http.Request) {
	body, _ := ioutil.ReadAll(req.Body)
	id, _ := noeqc.GenOne()

	stringId := fmt.Sprintf("%d", id)
	stringBody := fmt.Sprintf("%s", body)

	_, err := riakc.StoreObject("data", stringId, stringBody)

	if err != nil {
		log.Print("[POST] 500 Server Error")
		http.Error(w, "Server Error", 500)
		return
	}

	log.Print("[POST] {id: ", stringId, "}, {body: ", stringBody, "}")

	io.WriteString(w, stringId)
}

func GetData(w http.ResponseWriter, req *http.Request) {
	stringId := req.URL.Query().Get(":id")

	data, err := riakc.FetchObject("data", stringId)
	if err != nil {
		log.Print(" [GET] 404 Not Found", string(data))
		http.NotFound(w, req)
		return
	}

	log.Print(" [GET] ", string(data))

	io.WriteString(w, string(data))
}

func main() {
	riakc, err = riakpbc.New("127.0.0.1:8087", 1e8, 1e8)
	if err != nil {
		log.Print(err)
		return
	}

	noeqc, err = noeq.New("", "127.0.0.1:4444")
	if err != nil {
		log.Print(err)
		return
	}

	err = riakc.Dial()
	if err != nil {
		log.Print(err)
		return
	}

	m := pat.New()
	m.Get("/id/new", http.HandlerFunc(GetId))
	m.Post("/data", http.HandlerFunc(PostData))
	m.Get("/data/:id", http.HandlerFunc(GetData))

	http.Handle("/", m)

	log.Print("[INFO] ...starting your shoebox....")

	err = http.ListenAndServe(":12345", nil)
	if err != nil {
		log.Fatal("ListenAndServe: ", err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"encoding/pem"
	"flag"
	"io/ioutil"
	"net"
	"os"

	"github.com/dadrian/downgrade-check/ztools/x509"
	"github.com/dadrian/downgrade-check/ztools/ztls"
	"github.com/zmap/zgrab/ztools/zlog"
)

type Flags struct {
	CertificateChainPath string
	KeyPath              string
	LogFileName          string
	ListenAddress        string
	ExportKeyPath        string
}

var flags Flags

func init() {
	flag.StringVar(&flags.CertificateChainPath, "certificate", "cert_chain.pem", "Path to certificate chain (PEM encoded)")
	flag.StringVar(&flags.KeyPath, "key", "key.pem", "Path to key corresponding to certificate (PEM encoded, decrypted)")
	flag.StringVar(&flags.ListenAddress, "listen-address", "127.0.0.1:443", "ip:port to listen on")
	flag.StringVar(&flags.LogFileName, "log-file", "-", "defaults to stderr")
	flag.StringVar(&flags.ExportKeyPath, "export-key", "export-key.pem", "Path to 512-bit key")
	flag.Parse()
}

type DowngradeLog struct {
	Host       string             `json:"ip_address"`
	Vulnerable bool               `json:"vulnerable"`
	Request    string             `json:"request,omitempty"`
	Ciphers    []ztls.CipherSuite `json:"ciphers,omitempty"`
	RawHello   []byte             `json:"raw_hello"`
}

var logChan chan DowngradeLog

func downgrade(c *ztls.Conn) error {
	defer c.Close()
	host, _, _ := net.SplitHostPort(c.RemoteAddr().String())
	entry := DowngradeLog{
		Host: host,
	}
	handshakeErr := c.Handshake()
	entry.Ciphers = c.ClientCiphers()
	entry.RawHello = c.ClientHelloRaw()
	if handshakeErr != nil {
		logChan <- entry
		return handshakeErr
	}
	entry.Vulnerable = true
	buf := make([]byte, 1024)
	n, _ := c.Read(buf)
	entry.Request = string(buf[0:n])
	c.Write([]byte("HTTP/1.1 200 OK\r\n"))
	c.Write([]byte("Connection: close\r\n"))
	c.Write([]byte("Content-Type: text/plain; charset=us/ascii\r\n"))
	c.Write([]byte("Content-Length: 11\r\n"))
	c.Write([]byte("\r\n"))
	c.Write([]byte("VULNERABLE!"))
	logChan <- entry
	return nil
}

func main() {
	tlsConfig := ztls.Config{}
	cert, certErr := ztls.LoadX509KeyPair(flags.CertificateChainPath, flags.KeyPath)
	if certErr != nil {
		zlog.Fatal(certErr.Error())
	}
	tlsConfig.Certificates = []ztls.Certificate{cert}

	encodedKey, readKeyErr := ioutil.ReadFile(flags.ExportKeyPath)
	if readKeyErr != nil {
		zlog.Fatal(readKeyErr.Error())
	}
	pemBlock, _ := pem.Decode(encodedKey)

	exportKey, decodeKeyErr := x509.ParsePKCS1PrivateKey(pemBlock.Bytes)
	if decodeKeyErr != nil {
		zlog.Fatal(decodeKeyErr.Error())
	}
	if exportKey.N.BitLen() != 512 {
		zlog.Fatal("export key is not 512 bits")
	}
	tlsConfig.ExportKey = exportKey

	logFile := os.Stderr
	if flags.LogFileName != "-" {
		f, err := os.Create(flags.LogFileName)
		if err != nil {
			zlog.Fatal(err.Error())
		}
		logFile = f
	}
	logChan = make(chan DowngradeLog, 1024)
	go func() {
		encoder := json.NewEncoder(logFile)
		for {
			entry := <-logChan
			encoder.Encode(entry)
		}
	}()

	listener, err := ztls.Listen("tcp", flags.ListenAddress, &tlsConfig)
	if err != nil {
		zlog.Fatal(err.Error())
	}
	for {
		conn, err := listener.Accept()
		if err != nil {
			zlog.Info(err.Error())
			continue
		}
		c := conn.(*ztls.Conn)
		go downgrade(c)
	}
}
<commit_msg>Add timestamp<commit_after>package main

import (
	"encoding/json"
	"encoding/pem"
	"flag"
	"io/ioutil"
	"net"
	"os"
	"time"

	"github.com/dadrian/downgrade-check/ztools/x509"
	"github.com/dadrian/downgrade-check/ztools/ztls"
	"github.com/zmap/zgrab/ztools/zlog"
)

type Flags struct {
	CertificateChainPath string
	KeyPath              string
	LogFileName          string
	ListenAddress        string
	ExportKeyPath        string
}

var flags Flags

func init() {
	flag.StringVar(&flags.CertificateChainPath, "certificate", "cert_chain.pem", "Path to certificate chain (PEM encoded)")
	flag.StringVar(&flags.KeyPath, "key", "key.pem", "Path to key corresponding to certificate (PEM encoded, decrypted)")
	flag.StringVar(&flags.ListenAddress, "listen-address", "127.0.0.1:443", "ip:port to listen on")
	flag.StringVar(&flags.LogFileName, "log-file", "-", "defaults to stderr")
	flag.StringVar(&flags.ExportKeyPath, "export-key", "export-key.pem", "Path to 512-bit key")
	flag.Parse()
}

type DowngradeLog struct {
	Host       string             `json:"ip_address"`
	Time       string             `json:"time"`
	Vulnerable bool               `json:"vulnerable"`
	Request    string             `json:"request,omitempty"`
	Ciphers    []ztls.CipherSuite `json:"ciphers,omitempty"`
	RawHello   []byte             `json:"raw_hello"`
}

var logChan chan DowngradeLog

func downgrade(c *ztls.Conn) error {
	defer c.Close()
	host, _, _ := net.SplitHostPort(c.RemoteAddr().String())
	entry := DowngradeLog{
		Host: host,
		Time: time.Now().Format(time.RFC3339),
	}
	handshakeErr := c.Handshake()
	entry.Ciphers = c.ClientCiphers()
	entry.RawHello = c.ClientHelloRaw()
	if handshakeErr != nil {
		logChan <- entry
		return handshakeErr
	}
	entry.Vulnerable = true
	buf := make([]byte, 1024)
	n, _ := c.Read(buf)
	entry.Request = string(buf[0:n])
	c.Write([]byte("HTTP/1.1 200 OK\r\n"))
	c.Write([]byte("Connection: close\r\n"))
	c.Write([]byte("Content-Type: text/plain; charset=us/ascii\r\n"))
	c.Write([]byte("Content-Length: 11\r\n"))
	c.Write([]byte("\r\n"))
	c.Write([]byte("VULNERABLE!"))
	logChan <- entry
	return nil
}

func main() {
	tlsConfig := ztls.Config{}
	cert, certErr := ztls.LoadX509KeyPair(flags.CertificateChainPath, flags.KeyPath)
	if certErr != nil {
		zlog.Fatal(certErr.Error())
	}
	tlsConfig.Certificates = []ztls.Certificate{cert}

	encodedKey, readKeyErr := ioutil.ReadFile(flags.ExportKeyPath)
	if readKeyErr != nil {
		zlog.Fatal(readKeyErr.Error())
	}
	pemBlock, _ := pem.Decode(encodedKey)

	exportKey, decodeKeyErr := x509.ParsePKCS1PrivateKey(pemBlock.Bytes)
	if decodeKeyErr != nil {
		zlog.Fatal(decodeKeyErr.Error())
	}
	if exportKey.N.BitLen() != 512 {
		zlog.Fatal("export key is not 512 bits")
	}
	tlsConfig.ExportKey = exportKey

	logFile := os.Stderr
	if flags.LogFileName != "-" {
		f, err := os.Create(flags.LogFileName)
		if err != nil {
			zlog.Fatal(err.Error())
		}
		logFile = f
	}
	logChan = make(chan DowngradeLog, 1024)
	go func() {
		encoder := json.NewEncoder(logFile)
		for {
			entry := <-logChan
			encoder.Encode(entry)
		}
	}()

	listener, err := ztls.Listen("tcp", flags.ListenAddress, &tlsConfig)
	if err != nil {
		zlog.Fatal(err.Error())
	}
	for {
		conn, err := listener.Accept()
		if err != nil {
			zlog.Info(err.Error())
			continue
		}
		c := conn.(*ztls.Conn)
		go downgrade(c)
	}
}
<|endoftext|>