<commit_before>//
// Copyright 2016 Authors of Cilium
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package main

import (
	"encoding/hex"
	"fmt"
	"os"

	"github.com/cilium/cilium/pkg/bpf"
	"github.com/urfave/cli"
)

func main() {
	app := cli.NewApp()
	app.Name = "bpf-map"
	app.Usage = "Generic tool to introspect BPF maps"
	app.UsageText = "bpf-map { dump | info | update | remove } <map file>"
	app.Version = "1.0"
	app.Commands = []cli.Command{
		{
			Name:      "dump",
			Aliases:   []string{"d"},
			Usage:     "Dump contents of map",
			ArgsUsage: "<map path>",
			Action:    dumpMap,
		},
		{
			Name:      "info",
			Aliases:   []string{"i"},
			Usage:     "Print metadata information of map",
			ArgsUsage: "<map path>",
			Action:    infoMap,
		},
		{
			Name:      "update",
			Aliases:   []string{"u"},
			Usage:     "Update a map entry with keys and values in hex",
			ArgsUsage: "<map path> <key> <value>",
			Action:    updateMap,
		},
		{
			Name:      "remove",
			Aliases:   []string{"r"},
			Usage:     "Remove a map entry (key in hex)",
			ArgsUsage: "<map path> <key>",
			Action:    deleteKey,
		},
	}

	app.Run(os.Args)
}

func dumpMap(ctx *cli.Context) {
	if len(ctx.Args()) < 1 {
		cli.ShowCommandHelp(ctx, "dump")
		os.Exit(1)
	}

	path := ctx.Args().Get(0)
	m, err := bpf.OpenMap(path)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Unable to open map %s: %s\n", path, err)
		os.Exit(1)
	}

	dumpit := func(key []byte, value []byte) (bpf.MapKey, bpf.MapValue, error) {
		fmt.Printf("Key:\n%sValue:\n%s\n", hex.Dump(key), hex.Dump(value))
		return nil, nil, nil
	}

	err = m.Dump(dumpit, nil)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Unable to dump map %s: %s\n", path, err)
		os.Exit(1)
	}
}

func infoMap(ctx *cli.Context) {
	if len(ctx.Args()) < 1 {
		cli.ShowCommandHelp(ctx, "info")
		os.Exit(1)
	}

	path := ctx.Args().Get(0)
	m, err := bpf.OpenMap(path)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Unable to open map %s: %s\n", path, err)
		os.Exit(1)
	}

	fmt.Printf("Type:\t\t%s\nKey size:\t%d\nValue size:\t%d\nMax entries:\t%d\nFlags:\t\t%#x\n",
		m.MapType.String(), m.KeySize, m.ValueSize, m.MaxEntries, m.Flags)
}

func updateMap(ctx *cli.Context) {
	if len(ctx.Args()) < 3 {
		cli.ShowCommandHelp(ctx, "update")
		os.Exit(1)
	}

	path := ctx.Args().Get(0)
	m, err := bpf.OpenMap(path)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Unable to open map %s: %s\n", path, err)
		os.Exit(1)
	}

	key, err := newByteValue(ctx.Args().Get(1), m.KeySize, m.ValueSize)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Invalid key: %s\n", err)
		os.Exit(1)
	}

	value, err := newByteValue(ctx.Args().Get(2), m.ValueSize, m.ValueSize)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Invalid value: %s\n", err)
		os.Exit(1)
	}

	if err := m.Update(key, value); err != nil {
		fmt.Fprintf(os.Stderr, "Unable to set key: %s\n", err)
		os.Exit(1)
	} else {
		fmt.Println("Updated")
	}
}

func deleteKey(ctx *cli.Context) {
	if len(ctx.Args()) < 2 {
		cli.ShowCommandHelp(ctx, "remove")
		os.Exit(1)
	}

	path := ctx.Args().Get(0)
	m, err := bpf.OpenMap(path)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Unable to open map %s: %s\n", path, err)
		os.Exit(1)
	}

	key, err := newByteValue(ctx.Args().Get(1), m.KeySize, m.ValueSize)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Invalid key: %s\n", err)
		os.Exit(1)
	}

	if err := m.Delete(key); err != nil {
		fmt.Fprintf(os.Stderr, "Unable to remove key: %s\n", err)
		os.Exit(1)
	} else {
		fmt.Println("Removed")
	}
}
<commit_msg>bpf-map: print owner prog type<commit_after>//
// Copyright 2016 Authors of Cilium
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"encoding/hex"
	"fmt"
	"os"

	"github.com/cilium/cilium/pkg/bpf"
	"github.com/urfave/cli"
)

func main() {
	app := cli.NewApp()
	app.Name = "bpf-map"
	app.Usage = "Generic tool to introspect BPF maps"
	app.UsageText = "bpf-map { dump | info | update | remove } <map file>"
	app.Version = "1.0"
	app.Commands = []cli.Command{
		{
			Name:      "dump",
			Aliases:   []string{"d"},
			Usage:     "Dump contents of map",
			ArgsUsage: "<map path>",
			Action:    dumpMap,
		},
		{
			Name:      "info",
			Aliases:   []string{"i"},
			Usage:     "Print metadata information of map",
			ArgsUsage: "<map path>",
			Action:    infoMap,
		},
		{
			Name:      "update",
			Aliases:   []string{"u"},
			Usage:     "Update a map entry with keys and values in hex",
			ArgsUsage: "<map path> <key> <value>",
			Action:    updateMap,
		},
		{
			Name:      "remove",
			Aliases:   []string{"r"},
			Usage:     "Remove a map entry (key in hex)",
			ArgsUsage: "<map path> <key>",
			Action:    deleteKey,
		},
	}

	app.Run(os.Args)
}

func dumpMap(ctx *cli.Context) {
	if len(ctx.Args()) < 1 {
		cli.ShowCommandHelp(ctx, "dump")
		os.Exit(1)
	}

	path := ctx.Args().Get(0)
	m, err := bpf.OpenMap(path)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Unable to open map %s: %s\n", path, err)
		os.Exit(1)
	}

	dumpit := func(key []byte, value []byte) (bpf.MapKey, bpf.MapValue, error) {
		fmt.Printf("Key:\n%sValue:\n%s\n", hex.Dump(key), hex.Dump(value))
		return nil, nil, nil
	}

	err = m.Dump(dumpit, nil)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Unable to dump map %s: %s\n", path, err)
		os.Exit(1)
	}
}

func infoMap(ctx *cli.Context) {
	if len(ctx.Args()) < 1 {
		cli.ShowCommandHelp(ctx, "info")
		os.Exit(1)
	}

	path := ctx.Args().Get(0)
	m, err := bpf.OpenMap(path)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Unable to open map %s: %s\n", path, err)
		os.Exit(1)
	}

	fmt.Printf("Type:\t\t%s\nKey size:\t%d\nValue size:\t%d\nMax entries:\t%d\nFlags:\t\t%#x\n",
		m.MapType.String(), m.KeySize, m.ValueSize, m.MaxEntries, m.Flags)

	fmt.Printf("Owner prog type:\t%s\n", m.OwnerProgType.String())
}

func updateMap(ctx *cli.Context) {
	if len(ctx.Args()) < 3 {
		cli.ShowCommandHelp(ctx, "update")
		os.Exit(1)
	}

	path := ctx.Args().Get(0)
	m, err := bpf.OpenMap(path)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Unable to open map %s: %s\n", path, err)
		os.Exit(1)
	}

	key, err := newByteValue(ctx.Args().Get(1), m.KeySize, m.ValueSize)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Invalid key: %s\n", err)
		os.Exit(1)
	}

	value, err := newByteValue(ctx.Args().Get(2), m.ValueSize, m.ValueSize)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Invalid value: %s\n", err)
		os.Exit(1)
	}

	if err := m.Update(key, value); err != nil {
		fmt.Fprintf(os.Stderr, "Unable to set key: %s\n", err)
		os.Exit(1)
	} else {
		fmt.Println("Updated")
	}
}

func deleteKey(ctx *cli.Context) {
	if len(ctx.Args()) < 2 {
		cli.ShowCommandHelp(ctx, "remove")
		os.Exit(1)
	}

	path := ctx.Args().Get(0)
	m, err := bpf.OpenMap(path)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Unable to open map %s: %s\n", path, err)
		os.Exit(1)
	}

	key, err := newByteValue(ctx.Args().Get(1), m.KeySize, m.ValueSize)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Invalid key: %s\n", err)
		os.Exit(1)
	}

	if err := m.Delete(key); err != nil {
		fmt.Fprintf(os.Stderr, "Unable to remove key: %s\n", err)
		os.Exit(1)
	} else {
		fmt.Println("Removed")
	}
}
<|endoftext|>


<commit_before>package main

import (
	"io"
	"log"
	"net/http"
	"net/http/fcgi"
	"os"
	"runtime"
)

var app_addr string

func init() {
	runtime.GOMAXPROCS(runtime.NumCPU())
	app_addr = os.Getenv("APP_ADDR") // e.g. "0.0.0.0:8080" or ""
}

func ServeHTTP(w http.ResponseWriter, r *http.Request) {
	headers := w.Header()
	headers.Add("Content-Type", "text/html")
	io.WriteString(w, "
Hello world from Go!
")
}

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

	var err error
	if app_addr != "" { // Run as a local web server
		err = http.ListenAndServe(app_addr, nil)
	} else { // Run as FCGI via standard I/O
		err = fcgi.Serve(nil, nil)
	}
	if err != nil {
		log.Fatal(err)
	}
}
<commit_msg>Display request information in hello world.<commit_after>package main

import (
	"fmt"
	"io"
	"log"
	"net/http"
	"net/http/fcgi"
	"os"
	"runtime"
)

var app_addr string

func init() {
	runtime.GOMAXPROCS(runtime.NumCPU())
	app_addr = os.Getenv("APP_ADDR") // e.g. "0.0.0.0:8080" or ""
}

func ServeHTTP(w http.ResponseWriter, r *http.Request) {
	headers := w.Header()
	headers.Add("Content-Type", "text/html")
	io.WriteString(w, "
Hello world from Go!

")
	io.WriteString(w, fmt.Sprintf("
Method	%s
", r.Method))
	io.WriteString(w, fmt.Sprintf("
URL	%s
", r.URL))
	io.WriteString(w, fmt.Sprintf("
URL.Path	%s
", r.URL.Path))
	io.WriteString(w, fmt.Sprintf("
Proto	%s
", r.Proto))
	io.WriteString(w, fmt.Sprintf("
Host	%s
", r.Host))
	io.WriteString(w, fmt.Sprintf("
RemoteAddr	%s
", r.RemoteAddr))
	io.WriteString(w, fmt.Sprintf("
RequestURI	%s
", r.RequestURI))
	io.WriteString(w, fmt.Sprintf("
Header	%s
", r.Header))
	io.WriteString(w, fmt.Sprintf("
Body	%s
", r.Body))
	io.WriteString(w, "
")
}

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

	var err error
	if app_addr != "" { // Run as a local web server
		err = http.ListenAndServe(app_addr, nil)
	} else { // Run as FCGI via standard I/O
		err = fcgi.Serve(nil, nil)
	}
	if err != nil {
		log.Fatal(err)
	}
}
<|endoftext|>


<commit_before>package user_agent_surfer

import (
	"regexp"
	"strconv"
	"strings"
)

// Browser struct contains the lowercase name of the browser, along
// with its major browser version number. Browser are grouped together without
// consideration for device. For example, Chrome (Chrome/43.0) and Chrome for iOS
// (CriOS/43.0) would both return as "chrome" (name) and 43 (version). Similarly
// Internet Explorer 11 and Edge 12 would return as "ie" and "11" or "12", respectively.
type Browser struct {
	Name    string
	Version int
}

// Retrieve the espoused major version of the browser if possible, prioritizing
// the "Version/#" UA attribute over others. Set to 0 if no version
// is obtainable. A lowercase browser name (string) and its
// version (int) is returned.
func (b *BrowserProfile) evalBrowser(ua string) (string, int) {

	// Narrow browser by engine, then inference from other key words
	if strings.Contains(ua, "blackberry") || strings.Contains(ua, "playbook") || strings.Contains(ua, "bb10") { //blackberry goes first because it reads as MSIE & Safari really well
		b.Browser.Name = "blackberry"
	} else if strings.Contains(ua, "applewebkit") {
		if strings.Contains(ua, "opr/") {
			b.Browser.Name = "opera"
		} else if strings.Contains(ua, "silk/") {
			b.Browser.Name = "silk"
		} else if strings.Contains(ua, "edge/") || strings.Contains(ua, "iemobile/") || strings.Contains(ua, "msie ") {
			b.Browser.Name = "ie"
		} else if strings.Contains(ua, "ucbrowser/") || strings.Contains(ua, "ucweb/") {
			b.Browser.Name = "ucbrowser"
			// UC Browser abbreviates OS names, so we need these custom ones:
			/*			if strings.Contains(ua, "adr ") {
							os = "android"
						} else if {

							} else if {

							}*/
		} else if strings.Contains(ua, "chrome/") || strings.Contains(ua, "crios/") || strings.Contains(ua, "chromium/") { //Edge, Silk and other chrome-identifying browsers must evaluate before chrome, unless we want to add more overhead
			b.Browser.Name = "chrome"
		} else if strings.Contains(ua, "android") && !strings.Contains(ua, "chrome/") && strings.Contains(ua, "version/") && !strings.Contains(ua, "like android") {
			// Android WebView on Android >= 4.4 is purposefully being identified as Chrome above -- https://developer.chrome.com/multidevice/webview/overview
			b.Browser.Name = "android"
		} else if strings.Contains(ua, "fxios") {
			b.Browser.Name = "firefox"
		} else if strings.Contains(ua, "like gecko") {
			// Safari is the most generic, archtypical User-Agent on the market -- it's identified by making sure effectively by checking for attribute purity. It's fingerprint should have 4 or 5 total x/y attributes, 'mobile/version' being optional
			safariId, _ := regexp.Compile("\\w{3}\\/\\d")
			safariFingerprint := len(safariId.FindAllString(ua, -1))

			if (safariFingerprint == 4 || safariFingerprint == 5) && strings.Contains(ua, "version/") && strings.Contains(ua, "safari/") && strings.Contains(ua, "mozilla/") && !strings.Contains(ua, "linux") && !strings.Contains(ua, "android") {
				b.Browser.Name = "safari"
			}
		}
	} else if strings.Contains(ua, "msie") || strings.Contains(ua, "trident") {
		b.Browser.Name = "ie"
	} else if strings.Contains(ua, "gecko") {
		if strings.Contains(ua, "firefox") || strings.Contains(ua, "iceweasel") || strings.Contains(ua, "seamonkey") || strings.Contains(ua, "icecat") {
			b.Browser.Name = "firefox"
		}
	} else if strings.Contains(ua, "presto") || strings.Contains(ua, "opera") {
		b.Browser.Name = "opera"
	} else if strings.Contains(ua, "nintendo") {
		b.Browser.Name = "nintendo"
	}

	// Find browser version using 3 methods in order:
	// 1st: look for generic version/#
	// 2nd: look for browser-specific instructions (e.g. chrome/34)
	// 3rd: infer from OS
	v := ""
	bVersion, _ := regexp.Compile("version/\\d+")

	// if there is a 'version/#' attribute with numeric version, use it
	if bVersion.MatchString(ua) {
		v = bVersion.FindString(ua)
		v = strings.Split(v, "/")[1]
	} else {
		switch b.Browser.Name {
		case "chrome":
			// match both chrome and crios
			v = getMajorVersion(ua, "(chrome|crios)/\\d+")
		case "ie":
			if strings.Contains(ua, "msie") || strings.Contains(ua, "edge") {
				v = getMajorVersion(ua, "(msie\\s|edge/)\\d+")
			} else {
				// switch based on trident version indicator https://en.wikipedia.org/wiki/Trident_(layout_engine)
				if strings.Contains(ua, "trident") {
					v = getMajorVersion(ua, "trident/\\d+")
					switch v {
					case "3":
						v = "7"
					case "4":
						v = "8"
					case "5":
						v = "9"
					case "6":
						v = "10"
					case "7":
						v = "11"
					}
				}
			}
			if v == "" {
				v = "0"
			}
		case "firefox":
			v = getMajorVersion(ua, "(firefox|fxios)/\\d+")
		case "ucbrowser":
			v = getMajorVersion(ua, "ucbrowser/\\d+")
		case "opera":
			if strings.Contains(ua, "opr/") {
				v = getMajorVersion(ua, "opr/\\d+")
			} else {
				v = getMajorVersion(ua, "opera/\\d+")
			}
		case "silk":
			v = getMajorVersion(ua, "silk/\\d+")
		case "nintendo":
			v = "0" //getMajorVersion(ua, "nintendobrowser/\\d+")
		//case "opera":
		// could be either version/x or opr/x
		default:
			v = "0"
		}
	}
	// backup plans if we still don't know the version: guestimate based on highest available to the device
	// if v == "0" {
	// 	switch b.OS.Name {
	// 		case "iOS":
	// 			switch os.version {
	// 				case 1:
	// 				case 2:
	// 				case 3:
	// 				case 4:
	// 				case 5:
	// 				case 6:
	// 				case 7:
	// 				case 8:
	// 				case 9:
	// 				case 10:
	// 		case "Android":
	// 			switch os.version {
	// 				case 1:
	// 				case 2:
	// 				case 3:
	// 				case 4:
	// 				case 5:
	// 				case 6:
	// 				case 7:
	// 				case 8:
	// 				case 9:
	// 				case 10:
	// 		case "OS X":
	// 			switch os.version {
	// 				case 1:
	// 				case 2:
	// 				case 3:
	// 				case 4:
	// 				case 5:
	// 				case 6:
	// 				case 7:
	// 				case 8:
	// 				case 9:
	// 				case 10:
	// 				case 11:
	// 	}
	// }

	// Handle no match
	if v == "" {
		v = "0"
	}
	if b.Browser.Name == "" {
		b.Browser.Name = "unknown"
	}

	b.Browser.Version, _ = strconv.Atoi(v)

	return b.Browser.Name, b.Browser.Version
}

// Subfunction of evalBrowser() that takes two parameters: regex (string) and
// user agent (string) and returns the number as a string. "0" denotes no version.
func getMajorVersion(ua string, match string) string {
	bVersion, _ := regexp.Compile(match)
	ver := bVersion.FindString(ua)

	if ver != "" {
		if strings.Contains(ver, "/") {
			ver = strings.Split(ver, "/")[1] //e.g. "version/10.0.2"
		} else if strings.Contains(ver, " ") {
			ver = strings.Split(ver, " ")[1] //e.g. "msie 10.0"
		} else {
			ver = "0"
		}
	}

	return ver
}
<commit_msg>+ older ucbrowser support<commit_after>package user_agent_surfer

import (
	"regexp"
	"strconv"
	"strings"
)

// Browser struct contains the lowercase name of the browser, along
// with its major browser version number. Browser are grouped together without
// consideration for device. For example, Chrome (Chrome/43.0) and Chrome for iOS
// (CriOS/43.0) would both return as "chrome" (name) and 43 (version). Similarly
// Internet Explorer 11 and Edge 12 would return as "ie" and "11" or "12", respectively.
type Browser struct {
	Name    string
	Version int
}

// Retrieve the espoused major version of the browser if possible, prioritizing
// the "Version/#" UA attribute over others. Set to 0 if no version
// is obtainable. A lowercase browser name (string) and its
// version (int) is returned.
func (b *BrowserProfile) evalBrowser(ua string) (string, int) {

	// Narrow browser by engine, then inference from other key words
	if strings.Contains(ua, "blackberry") || strings.Contains(ua, "playbook") || strings.Contains(ua, "bb10") { //blackberry goes first because it reads as MSIE & Safari really well
		b.Browser.Name = "blackberry"
	} else if strings.Contains(ua, "applewebkit") {
		if strings.Contains(ua, "opr/") {
			b.Browser.Name = "opera"
		} else if strings.Contains(ua, "silk/") {
			b.Browser.Name = "silk"
		} else if strings.Contains(ua, "edge/") || strings.Contains(ua, "iemobile/") || strings.Contains(ua, "msie ") {
			b.Browser.Name = "ie"
		} else if strings.Contains(ua, "ucbrowser/") || strings.Contains(ua, "ucweb/") {
			b.Browser.Name = "ucbrowser"
			// UC Browser abbreviates OS names, so we need these custom ones:
			/*			if strings.Contains(ua, "adr ") {
							os = "android"
						} else if {

							} else if {

							}*/
		} else if strings.Contains(ua, "chrome/") || strings.Contains(ua, "crios/") || strings.Contains(ua, "chromium/") { //Edge, Silk and other chrome-identifying browsers must evaluate before chrome, unless we want to add more overhead
			b.Browser.Name = "chrome"
		} else if strings.Contains(ua, "android") && !strings.Contains(ua, "chrome/") && strings.Contains(ua, "version/") && !strings.Contains(ua, "like android") {
			// Android WebView on Android >= 4.4 is purposefully being identified as Chrome above -- https://developer.chrome.com/multidevice/webview/overview
			b.Browser.Name = "android"
		} else if strings.Contains(ua, "fxios") {
			b.Browser.Name = "firefox"
		} else if strings.Contains(ua, "like gecko") {
			// Safari is the most generic, archtypical User-Agent on the market -- it's identified by making sure effectively by checking for attribute purity. It's fingerprint should have 4 or 5 total x/y attributes, 'mobile/version' being optional
			safariId, _ := regexp.Compile("\\w{3}\\/\\d")
			safariFingerprint := len(safariId.FindAllString(ua, -1))

			if (safariFingerprint == 4 || safariFingerprint == 5) && strings.Contains(ua, "version/") && strings.Contains(ua, "safari/") && strings.Contains(ua, "mozilla/") && !strings.Contains(ua, "linux") && !strings.Contains(ua, "android") {
				b.Browser.Name = "safari"
			}
		}
	} else if strings.Contains(ua, "msie") || strings.Contains(ua, "trident") {
		b.Browser.Name = "ie"
	} else if strings.Contains(ua, "gecko") {
		if strings.Contains(ua, "firefox") || strings.Contains(ua, "iceweasel") || strings.Contains(ua, "seamonkey") || strings.Contains(ua, "icecat") {
			b.Browser.Name = "firefox"
		}
	} else if strings.Contains(ua, "presto") || strings.Contains(ua, "opera") {
		b.Browser.Name = "opera"
	} else if strings.Contains(ua, "ucbrowser") {
		b.Browser.Name = "ucbrowser"
	} else if strings.Contains(ua, "nintendo") {
		b.Browser.Name = "nintendo"
	}

	// Find browser version using 3 methods in order:
	// 1st: look for generic version/#
	// 2nd: look for browser-specific instructions (e.g. chrome/34)
	// 3rd: infer from OS
	v := ""
	bVersion, _ := regexp.Compile("version/\\d+")

	// if there is a 'version/#' attribute with numeric version, use it
	if bVersion.MatchString(ua) {
		v = bVersion.FindString(ua)
		v = strings.Split(v, "/")[1]
	} else {
		switch b.Browser.Name {
		case "chrome":
			// match both chrome and crios
			v = getMajorVersion(ua, "(chrome|crios)/\\d+")
		case "ie":
			if strings.Contains(ua, "msie") || strings.Contains(ua, "edge") {
				v = getMajorVersion(ua, "(msie\\s|edge/)\\d+")
			} else {
				// switch based on trident version indicator https://en.wikipedia.org/wiki/Trident_(layout_engine)
				if strings.Contains(ua, "trident") {
					v = getMajorVersion(ua, "trident/\\d+")
					switch v {
					case "3":
						v = "7"
					case "4":
						v = "8"
					case "5":
						v = "9"
					case "6":
						v = "10"
					case "7":
						v = "11"
					}
				}
			}
			if v == "" {
				v = "0"
			}
		case "firefox":
			v = getMajorVersion(ua, "(firefox|fxios)/\\d+")
		case "ucbrowser":
			v = getMajorVersion(ua, "ucbrowser/\\d+")
		case "opera":
			if strings.Contains(ua, "opr/") {
				v = getMajorVersion(ua, "opr/\\d+")
			} else {
				v = getMajorVersion(ua, "opera/\\d+")
			}
		case "silk":
			v = getMajorVersion(ua, "silk/\\d+")
		case "nintendo":
			v = "0" //getMajorVersion(ua, "nintendobrowser/\\d+")
		//case "opera":
		// could be either version/x or opr/x
		default:
			v = "0"
		}
	}
	// backup plans if we still don't know the version: guestimate based on highest available to the device
	// if v == "0" {
	// 	switch b.OS.Name {
	// 		case "iOS":
	// 			switch os.version {
	// 				case 1:
	// 				case 2:
	// 				case 3:
	// 				case 4:
	// 				case 5:
	// 				case 6:
	// 				case 7:
	// 				case 8:
	// 				case 9:
	// 				case 10:
	// 		case "Android":
	// 			switch os.version {
	// 				case 1:
	// 				case 2:
	// 				case 3:
	// 				case 4:
	// 				case 5:
	// 				case 6:
	// 				case 7:
	// 				case 8:
	// 				case 9:
	// 				case 10:
	// 		case "OS X":
	// 			switch os.version {
	// 				case 1:
	// 				case 2:
	// 				case 3:
	// 				case 4:
	// 				case 5:
	// 				case 6:
	// 				case 7:
	// 				case 8:
	// 				case 9:
	// 				case 10:
	// 				case 11:
	// 	}
	// }

	// Handle no match
	if v == "" {
		v = "0"
	}
	if b.Browser.Name == "" {
		b.Browser.Name = "unknown"
	}

	b.Browser.Version, _ = strconv.Atoi(v)

	return b.Browser.Name, b.Browser.Version
}

// Subfunction of evalBrowser() that takes two parameters: regex (string) and
// user agent (string) and returns the number as a string. "0" denotes no version.
func getMajorVersion(ua string, match string) string {
	bVersion, _ := regexp.Compile(match)
	ver := bVersion.FindString(ua)

	if ver != "" {
		if strings.Contains(ver, "/") {
			ver = strings.Split(ver, "/")[1] //e.g. "version/10.0.2"
		} else if strings.Contains(ver, " ") {
			ver = strings.Split(ver, " ")[1] //e.g. "msie 10.0"
		} else {
			ver = "0"
		}
	}

	return ver
}
<|endoftext|>


<commit_before>package executil

import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"os/exec"
	"unicode/utf8"
)

func FormatCommand(cmd *exec.Cmd) (string, error) {
	var out bytes.Buffer
	for i, arg := range cmd.Args {
		if i > 0 {
			out.WriteRune(' ')
		}
		err := WriteWord(&out, arg)
		if err != nil {
			return "", err
		}
	}
	return out.String(), nil
}

func WriteWord(output *bytes.Buffer, word string) error {
	return newEscaper(word, output).run()
}

// escaper

type escaper struct {
	input      string
	start      int
	pos        int
	width      int
	output     *bytes.Buffer
	state      stateFn
	quoteStack runeStack
	err        error
}

type stateFn func(*escaper) stateFn

func newEscaper(input string, output *bytes.Buffer) *escaper {
	return &escaper{
		input:   input,
		output:  output,
	}
}

func (e *escaper) run() error {
	for e.state = scanText; e.state != nil; {
		e.state = e.state(e)
	}
	return e.err
}

func (e *escaper) readRune() (r rune, size int, err error) {
	if e.pos >= len(e.input) {
		e.width = 0
		err = io.EOF
		return
	}
	r, size = utf8.DecodeRuneInString(e.input[e.pos:])
	e.width = size
	e.pos += size
	return
}

func (e *escaper) unreadRune() error {
	if e.pos <= e.start {
		return errors.New("cannot unreadRune()")
	}
	e.pos -= e.width
	return nil
}

func (e *escaper) writeRune(r rune) (n int, err error) {
	return e.output.WriteRune(r)
}

func scanText(e *escaper) stateFn {
	r, _, err := e.readRune()
	if err == io.EOF {
		return nil
	}
	switch r {
	case ' ':
		e.writeRune('\\')
		e.writeRune(r)
		return scanText
	case '"', '\'':
		e.quoteStack.push(r)
		e.writeRune(r)
		return scanInsideQuote
	case '\\':
		e.writeRune('\\')
		r, _, err = e.readRune()
		if err == io.EOF {
			e.err = fmt.Errorf("character needed after backslash: %s.", e.input)
			return nil
		}
		e.writeRune(r)
		return scanText
	default:
		e.writeRune(r)
		return scanText
	}
}

func scanInsideQuote(e *escaper) stateFn {
	r, _, err := e.readRune()
	if err == io.EOF {
		e.err = fmt.Errorf("quote not closed: %s.", e.input)
		return nil
	}
	switch r {
	case e.quoteStack.peek():
		e.quoteStack.pop()
		e.writeRune(r)
		if e.quoteStack.isEmpty() {
			return scanText
		} else {
			return scanInsideQuote
		}
	case '\\':
		e.writeRune(r)
		r, _, err = e.readRune()
		if err == io.EOF {
			e.err = fmt.Errorf("character needed after backslash: %s.", e.input)
			return nil
		}
		e.writeRune(r)
		return scanInsideQuote
	default:
		e.writeRune(r)
		return scanInsideQuote
	}
}

// runeStack

type runeStack struct {
	runes []rune
}

func (s *runeStack) isEmpty() bool {
	return len(s.runes) == 0
}

func (s *runeStack) push(r rune) {
	s.runes = append(s.runes, r)
}

func (s *runeStack) pop() rune {
	r := s.peek()
	s.runes = s.runes[:len(s.runes)-1]
	return r
}

func (s *runeStack) peek() rune {
	return s.runes[len(s.runes)-1]
}
<commit_msg>Change FormatCommand to use double quotes to quote words with spaces in them.<commit_after>package executil

import (
	"bytes"
	"os/exec"
	"strings"
)

func FormatCommand(cmd *exec.Cmd) (string, error) {
	var out bytes.Buffer
	for i, arg := range cmd.Args {
		if i > 0 {
			out.WriteRune(' ')
		}
		out.WriteString(quoteWord(arg))
	}
	return out.String(), nil
}

func quoteWord(word string) string {
	if strings.ContainsAny(word, `'" `) {
		return `"` + strings.Replace(word, `"`, `\"`, -1) + `"`
	} else {
		return word
	}
}
<|endoftext|>


<commit_before>package gog

import (
	"fmt"
	"go/ast"
	"go/parser"
	"io/ioutil"
	"testing"

	"code.google.com/p/go.tools/go/loader"
)

func graphPkgFromFiles(t *testing.T, path string, filenames []string) (*Grapher, *loader.Program) {
	prog := createPkgFromFiles(t, path, filenames)
	g := New(prog)
	err := g.GraphAll()
	if err != nil {
		t.Fatal(err)
	}
	return g, prog
}

func createPkgFromFiles(t *testing.T, path string, filenames []string) *loader.Program {
	sources := make([]string, len(filenames))
	for i, file := range filenames {
		src, err := ioutil.ReadFile(file)
		if err != nil {
			t.Fatal(err)
		}
		sources[i] = string(src)
	}
	return createPkg(t, path, sources, filenames)
}

func createPkg(t *testing.T, path string, sources []string, names []string) *loader.Program {
	conf := Default
	conf.SourceImports = *resolve

	var files []*ast.File
	for i, src := range sources {
		var name string
		if i < len(names) {
			name = names[i]
		} else {
			name = fmt.Sprintf("sources[%d]", i)
		}
		f, err := conf.ParseFile(name, src, parser.DeclarationErrors)
		if err != nil {
			t.Fatal(err)
		}
		files = append(files, f)
	}

	conf.CreateFromFiles(path, files...)
	prog, err := conf.Load()
	if err != nil {
		t.Fatal(err)
	}
	conf.Import("builtin")

	return prog
}
<commit_msg>update call - go.tools got updated<commit_after>package gog

import (
	"fmt"
	"go/ast"
	"io/ioutil"
	"testing"

	"code.google.com/p/go.tools/go/loader"
)

func graphPkgFromFiles(t *testing.T, path string, filenames []string) (*Grapher, *loader.Program) {
	prog := createPkgFromFiles(t, path, filenames)
	g := New(prog)
	err := g.GraphAll()
	if err != nil {
		t.Fatal(err)
	}
	return g, prog
}

func createPkgFromFiles(t *testing.T, path string, filenames []string) *loader.Program {
	sources := make([]string, len(filenames))
	for i, file := range filenames {
		src, err := ioutil.ReadFile(file)
		if err != nil {
			t.Fatal(err)
		}
		sources[i] = string(src)
	}
	return createPkg(t, path, sources, filenames)
}

func createPkg(t *testing.T, path string, sources []string, names []string) *loader.Program {
	conf := Default
	conf.SourceImports = *resolve

	var files []*ast.File
	for i, src := range sources {
		var name string
		if i < len(names) {
			name = names[i]
		} else {
			name = fmt.Sprintf("sources[%d]", i)
		}
		f, err := conf.ParseFile(name, src)
		if err != nil {
			t.Fatal(err)
		}
		files = append(files, f)
	}

	conf.CreateFromFiles(path, files...)
	prog, err := conf.Load()
	if err != nil {
		t.Fatal(err)
	}
	conf.Import("builtin")

	return prog
}
<|endoftext|>


<commit_before>package apptail

import (
	"fmt"
	"github.com/ActiveState/log"
	"github.com/ActiveState/tail"
	"github.com/ActiveState/zmqpubsub"
	"logyard"
	"logyard/clients/messagecommon"
	"os"
	"path/filepath"
	"strings"
	"time"
)

// Instance is the NATS message sent by dea_ng to notify of new instances.
type Instance struct {
	AppGUID  string
	AppName  string
	AppSpace string
	Type     string
	Index    int
	DockerId string `json:"docker_id"`
	RootPath string
	LogFiles map[string]string
}

func (instance *Instance) Identifier() string {
	return fmt.Sprintf("%v[%v:%v]", instance.AppName, instance.Index, instance.DockerId[:ID_LENGTH])
}

// Tail begins tailing the files for this instance.
func (instance *Instance) Tail() {
	log.Infof("Tailing %v logs for %v -- %+v",
		instance.Type, instance.Identifier(), instance)

	stopCh := make(chan bool)
	logfiles := instance.getLogFiles()

	log.Infof("Determined log files: %+v", logfiles)

	for name, filename := range logfiles {
		go instance.tailFile(name, filename, stopCh)
	}

	go func() {
		DockerListener.WaitForContainer(instance.DockerId)
		log.Infof("Container for %v exited", instance.Identifier())
		close(stopCh)
	}()
}

func (instance *Instance) tailFile(name, filename string, stopCh chan bool) {
	var err error

	pub := logyard.Broker.NewPublisherMust()
	defer pub.Stop()

	limit, err := instance.getReadLimit(pub, name, filename)
	if err != nil {
		log.Warn(err)
		return
	}

	t, err := tail.TailFile(filename, tail.Config{
		MaxLineSize: GetConfig().MaxRecordSize,
		MustExist:   true,
		Follow:      true,
		Location:    &tail.SeekInfo{-limit, os.SEEK_END},
		ReOpen:      false,
		Poll:        false,
		LimitRate:   GetConfig().RateLimit})
	if err != nil {
		log.Warnf("Cannot tail file (%s); %s", filename, err)
		return
	}

FORLOOP:
	for {
		select {
		case line, ok := <-t.Lines:
			if !ok {
				err = t.Wait()
				break FORLOOP
			}
			instance.publishLine(pub, name, line)
		case <-stopCh:
			err = t.Stop()
			break FORLOOP
		}
	}

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

	log.Infof("Completed tailing %v log for %v", name, instance.Identifier())
}

func (instance *Instance) getLogFiles() map[string]string {
	var logfiles map[string]string

	rawMode := len(instance.LogFiles) > 0
	if rawMode {
		// If the logfiles list was explicitly passed, use it as is.
		logfiles = instance.LogFiles
	} else {
		// Use $STACKATO_LOG_FILES
		logfiles = make(map[string]string)
		if env, err := GetDockerAppEnv(instance.RootPath); err != nil {
			log.Errorf("Failed to read docker image env: %v", err)
		} else {
			if s, ok := env["STACKATO_LOG_FILES"]; ok {
				parts := strings.Split(s, ":")
				if len(parts) > 7 {
					log.Warnf("$STACKATO_LOG_FILES contains more than 7 parts; using only last 7 parts")
					parts = parts[len(parts)-7 : len(parts)]
				}
				for _, f := range parts {
					parts := strings.SplitN(f, "=", 2)
					logfiles[parts[0]] = parts[1]
				}
			} else {
				log.Errorf("Expected env $STACKATO_LOG_FILES not found in docker image")
			}
		}
	}

	pub := logyard.Broker.NewPublisherMust()
	defer pub.Stop()
	// XXX: this delay is unfortunately required, else the publish calls
	// (instance.notify) below for warnings will get ignored.
	time.Sleep(100 * time.Millisecond)

	// Expand paths, and securely ensure they fall within the app root.
	logfilesSecure := make(map[string]string)
	for name, path := range logfiles {
		// Treat relative paths as being relative to the app directory.
		if !filepath.IsAbs(path) {
			path = filepath.Join("/app/app/", path)
		}

		fullpath := filepath.Join(instance.RootPath, path)
		fullpath, err := filepath.Abs(fullpath)
		if err != nil {
			log.Warnf("Cannot find Abs of %v <join> %v: %v", instance.RootPath, path, err)
			instance.notify(pub, fmt.Sprintf("WARN -- Failed to find absolute path for %v", path))
			continue
		}
		fullpath, err = filepath.EvalSymlinks(fullpath)
		if err != nil {
			instance.notify(pub, fmt.Sprintf("WARN -- Ignoring inaccessible, nonexistent or insecure path %v", path))
			continue
		}
		if !strings.HasPrefix(fullpath, instance.RootPath) {
			log.Warnf("Ignoring insecure log path %v (via %v) in instance %+v", fullpath, path, instance)
			// This user warning is exactly the same as above, lest we provide
			// a backdoor for a malicious user to list the directory tree on
			// the host.
			instance.notify(pub, fmt.Sprintf("WARN -- Ignoring inaccessible, nonexistent or insecure path %v", path))
			continue
		}
		logfilesSecure[name] = fullpath
	}

	return logfilesSecure
}

func (instance *Instance) getReadLimit(
	pub *zmqpubsub.Publisher,
	logname string,
	filename string) (int64, error) {
	// convert MB to limit in bytes.
	filesizeLimit := GetConfig().FileSizeLimit * 1024 * 1024
	if !(filesizeLimit > 0) {
		panic("invalid value for `read_limit' in apptail config")
	}

	fi, err := os.Stat(filename)
	if err != nil {
		return -1, fmt.Errorf("Cannot stat file (%s); %s", filename, err)
	}
	size := fi.Size()
	limit := filesizeLimit
	if size > filesizeLimit {
		err := fmt.Errorf("Skipping much of a large log file (%s); size (%v bytes) > read_limit (%v bytes)",
			logname, size, filesizeLimit)
		// Publish special error message.
		instance.publishLine(pub, logname, &tail.Line{
			Text: err.Error(),
			Time: time.Now(),
			Err:  err})
	} else {
		limit = size
	}
	return limit, nil
}

// publishLine publishes a log line corresponding to this instance.
func (instance *Instance) publishLine(pub *zmqpubsub.Publisher, logname string, line *tail.Line) {
	instance.publishLineAs(pub, instance.Type, logname, line)
}

func (instance *Instance) notify(pub *zmqpubsub.Publisher, line string) {
	instance.publishLineAs(pub, "stackato.apptail", "", tail.NewLine(line))
}

func (instance *Instance) publishLineAs(pub *zmqpubsub.Publisher, source string, logname string, line *tail.Line) {
	if line == nil {
		panic("line is nil")
	}

	msg := &Message{
		LogFilename:   logname,
		Source:        source,
		InstanceIndex: instance.Index,
		AppGUID:       instance.AppGUID,
		AppName:       instance.AppName,
		AppSpace:      instance.AppSpace,
		MessageCommon: messagecommon.New(line.Text, line.Time, LocalNodeId()),
	}

	if line.Err != nil {
		// Mark this as a special error record, as it is
		// coming from tail, not the app.
		msg.Source = "stackato.apptail"
		msg.LogFilename = ""
		log.Warnf("[%s] %s", instance.AppName, line.Text)
	}

	err := msg.Publish(pub, false)
	if err != nil {
		Fatal("unable to publish: %v", err)
	}
}
<commit_msg>simplify user warning here<commit_after>package apptail

import (
	"fmt"
	"github.com/ActiveState/log"
	"github.com/ActiveState/tail"
	"github.com/ActiveState/zmqpubsub"
	"logyard"
	"logyard/clients/messagecommon"
	"os"
	"path/filepath"
	"strings"
	"time"
)

// Instance is the NATS message sent by dea_ng to notify of new instances.
type Instance struct {
	AppGUID  string
	AppName  string
	AppSpace string
	Type     string
	Index    int
	DockerId string `json:"docker_id"`
	RootPath string
	LogFiles map[string]string
}

func (instance *Instance) Identifier() string {
	return fmt.Sprintf("%v[%v:%v]", instance.AppName, instance.Index, instance.DockerId[:ID_LENGTH])
}

// Tail begins tailing the files for this instance.
func (instance *Instance) Tail() {
	log.Infof("Tailing %v logs for %v -- %+v",
		instance.Type, instance.Identifier(), instance)

	stopCh := make(chan bool)
	logfiles := instance.getLogFiles()

	log.Infof("Determined log files: %+v", logfiles)

	for name, filename := range logfiles {
		go instance.tailFile(name, filename, stopCh)
	}

	go func() {
		DockerListener.WaitForContainer(instance.DockerId)
		log.Infof("Container for %v exited", instance.Identifier())
		close(stopCh)
	}()
}

func (instance *Instance) tailFile(name, filename string, stopCh chan bool) {
	var err error

	pub := logyard.Broker.NewPublisherMust()
	defer pub.Stop()

	limit, err := instance.getReadLimit(pub, name, filename)
	if err != nil {
		log.Warn(err)
		return
	}

	t, err := tail.TailFile(filename, tail.Config{
		MaxLineSize: GetConfig().MaxRecordSize,
		MustExist:   true,
		Follow:      true,
		Location:    &tail.SeekInfo{-limit, os.SEEK_END},
		ReOpen:      false,
		Poll:        false,
		LimitRate:   GetConfig().RateLimit})
	if err != nil {
		log.Warnf("Cannot tail file (%s); %s", filename, err)
		return
	}

FORLOOP:
	for {
		select {
		case line, ok := <-t.Lines:
			if !ok {
				err = t.Wait()
				break FORLOOP
			}
			instance.publishLine(pub, name, line)
		case <-stopCh:
			err = t.Stop()
			break FORLOOP
		}
	}

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

	log.Infof("Completed tailing %v log for %v", name, instance.Identifier())
}

func (instance *Instance) getLogFiles() map[string]string {
	var logfiles map[string]string

	rawMode := len(instance.LogFiles) > 0
	if rawMode {
		// If the logfiles list was explicitly passed, use it as is.
		logfiles = instance.LogFiles
	} else {
		// Use $STACKATO_LOG_FILES
		logfiles = make(map[string]string)
		if env, err := GetDockerAppEnv(instance.RootPath); err != nil {
			log.Errorf("Failed to read docker image env: %v", err)
		} else {
			if s, ok := env["STACKATO_LOG_FILES"]; ok {
				parts := strings.Split(s, ":")
				if len(parts) > 7 {
					log.Warnf("$STACKATO_LOG_FILES contains more than 7 parts; using only last 7 parts")
					parts = parts[len(parts)-7 : len(parts)]
				}
				for _, f := range parts {
					parts := strings.SplitN(f, "=", 2)
					logfiles[parts[0]] = parts[1]
				}
			} else {
				log.Errorf("Expected env $STACKATO_LOG_FILES not found in docker image")
			}
		}
	}

	pub := logyard.Broker.NewPublisherMust()
	defer pub.Stop()
	// XXX: this delay is unfortunately required, else the publish calls
	// (instance.notify) below for warnings will get ignored.
	time.Sleep(100 * time.Millisecond)

	// Expand paths, and securely ensure they fall within the app root.
	logfilesSecure := make(map[string]string)
	for name, path := range logfiles {
		// Treat relative paths as being relative to the app directory.
		if !filepath.IsAbs(path) {
			path = filepath.Join("/app/app/", path)
		}

		fullpath := filepath.Join(instance.RootPath, path)
		fullpath, err := filepath.Abs(fullpath)
		if err != nil {
			log.Warnf("Cannot find Abs of %v <join> %v: %v", instance.RootPath, path, err)
			instance.notify(pub, fmt.Sprintf("WARN -- Failed to find absolute path for %v", path))
			continue
		}
		fullpath, err = filepath.EvalSymlinks(fullpath)
		if err != nil {
			instance.notify(pub, fmt.Sprintf("WARN -- Ignoring missing/inaccessible path %v", path))
			continue
		}
		if !strings.HasPrefix(fullpath, instance.RootPath) {
			log.Warnf("Ignoring insecure log path %v (via %v) in instance %+v", fullpath, path, instance)
			// This user warning is exactly the same as above, lest we provide
			// a backdoor for a malicious user to list the directory tree on
			// the host.
			instance.notify(pub, fmt.Sprintf("WARN -- Ignoring missing/inaccessible path %v", path))
			continue
		}
		logfilesSecure[name] = fullpath
	}

	return logfilesSecure
}

func (instance *Instance) getReadLimit(
	pub *zmqpubsub.Publisher,
	logname string,
	filename string) (int64, error) {
	// convert MB to limit in bytes.
	filesizeLimit := GetConfig().FileSizeLimit * 1024 * 1024
	if !(filesizeLimit > 0) {
		panic("invalid value for `read_limit' in apptail config")
	}

	fi, err := os.Stat(filename)
	if err != nil {
		return -1, fmt.Errorf("Cannot stat file (%s); %s", filename, err)
	}
	size := fi.Size()
	limit := filesizeLimit
	if size > filesizeLimit {
		err := fmt.Errorf("Skipping much of a large log file (%s); size (%v bytes) > read_limit (%v bytes)",
			logname, size, filesizeLimit)
		// Publish special error message.
		instance.publishLine(pub, logname, &tail.Line{
			Text: err.Error(),
			Time: time.Now(),
			Err:  err})
	} else {
		limit = size
	}
	return limit, nil
}

// publishLine publishes a log line corresponding to this instance.
func (instance *Instance) publishLine(pub *zmqpubsub.Publisher, logname string, line *tail.Line) {
	instance.publishLineAs(pub, instance.Type, logname, line)
}

func (instance *Instance) notify(pub *zmqpubsub.Publisher, line string) {
	instance.publishLineAs(pub, "stackato.apptail", "", tail.NewLine(line))
}

func (instance *Instance) publishLineAs(pub *zmqpubsub.Publisher, source string, logname string, line *tail.Line) {
	if line == nil {
		panic("line is nil")
	}

	msg := &Message{
		LogFilename:   logname,
		Source:        source,
		InstanceIndex: instance.Index,
		AppGUID:       instance.AppGUID,
		AppName:       instance.AppName,
		AppSpace:      instance.AppSpace,
		MessageCommon: messagecommon.New(line.Text, line.Time, LocalNodeId()),
	}

	if line.Err != nil {
		// Mark this as a special error record, as it is
		// coming from tail, not the app.
		msg.Source = "stackato.apptail"
		msg.LogFilename = ""
		log.Warnf("[%s] %s", instance.AppName, line.Text)
	}

	err := msg.Publish(pub, false)
	if err != nil {
		Fatal("unable to publish: %v", err)
	}
}
<|endoftext|>


<commit_before>package postgresql

import (
	_ "github.com/lib/pq"
	"database/sql"
	"fmt"
)

func New(dbname, user, pass string){
	db, err := sql.Open("postgres", fmt.Sprintf("dbname=%s user=%s password=%s sslmode=disable", dbname, user, pass))
	if err != nil {
		panic(err)
	}
	defer db.Close()
}
<commit_msg>formatted<commit_after>package postgresql

import (
	"database/sql"
	"fmt"
	_ "github.com/lib/pq"
)

func New(dbname, user, pass string) {
	db, err := sql.Open("postgres", fmt.Sprintf("dbname=%s user=%s password=%s sslmode=disable", dbname, user, pass))
	if err != nil {
		panic(err)
	}
	defer db.Close()
}
<|endoftext|>


<commit_before>package jobsupervisor_test

import (
	"encoding/json"
	"fmt"
	"os"
	"path"
	"path/filepath"
	"runtime"
	"time"

	boshdirs "github.com/cloudfoundry/bosh-agent/settings/directories"
	boshlog "github.com/cloudfoundry/bosh-utils/logger"
	boshsys "github.com/cloudfoundry/bosh-utils/system"

	. "github.com/cloudfoundry/bosh-agent/jobsupervisor"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("WindowsJobSupervisor", func() {
	Context("add jobs and control services", func() {
		BeforeEach(func() {
			if runtime.GOOS != "windows" {
				Skip("Pending on non-Windows")
			}
		})

		var (
			runner            boshsys.CmdRunner
			fs                boshsys.FileSystem
			jobSupervisor     JobSupervisor
			jobDir            string
			processConfigPath string
			basePath          string
			exePath           string
			logDir            string
			exePathNotExist   bool
			configContents    WindowsProcessConfig
		)

		AddJob := func() error {
			return jobSupervisor.AddJob("say-hello", 0, processConfigPath)
		}

		BeforeEach(func() {
			logger := boshlog.NewLogger(boshlog.LevelNone)
			fs = boshsys.NewOsFileSystem(logger)

			basePath = "C:/var/vcap/"
			fs.MkdirAll(basePath, 0755)

			binPath := filepath.Join(basePath, "bosh", "bin")
			fs.MkdirAll(binPath, 0755)

			logDir = path.Join(basePath, "sys", "log")
			fs.MkdirAll(binPath, 0755)

			const testExtPath = "testdata/job-service-wrapper"
			exePath = filepath.Join(binPath, "job-service-wrapper.exe")

			_, err := os.Stat(exePath)
			exePathNotExist = os.IsNotExist(err)
			if exePathNotExist {
				Expect(fs.CopyFile(testExtPath, exePath)).ToNot(HaveOccurred())
			}

			logDir = path.Join(basePath, "sys", "log")

			configContents = WindowsProcessConfig{
				Processes: []WindowsProcess{
					{
						Name:       fmt.Sprintf("say-hello-1-%d", time.Now().UnixNano()),
						Executable: "powershell",
						Args:       []string{"/C", "Write-Host \"Hello 1\"; Start-Sleep 10"},
					},
					{
						Name:       fmt.Sprintf("say-hello-2-%d", time.Now().UnixNano()),
						Executable: "powershell",
						Args:       []string{"/C", "Write-Host \"Hello 2\"; Start-Sleep 10"},
					},
				},
			}

			processConfigContents, err := json.Marshal(configContents)
			Expect(err).ToNot(HaveOccurred())

			dirProvider := boshdirs.NewProvider(basePath)

			runner = boshsys.NewExecCmdRunner(logger)
			jobSupervisor = NewWindowsJobSupervisor(runner, dirProvider, fs, logger)
			jobSupervisor.RemoveAllJobs()

			jobDir, err = fs.TempDir("testWindowsJobSupervisor")
			processConfigPath = filepath.Join(jobDir, "monit")

			err = fs.WriteFile(processConfigPath, processConfigContents)
			Expect(err).ToNot(HaveOccurred())
		})

		AfterEach(func() {
			jobSupervisor.Stop()
			jobSupervisor.RemoveAllJobs()
			fs.RemoveAll(jobDir)
			fs.RemoveAll(logDir)
			if exePathNotExist {
				fs.RemoveAll(exePath)
			}
		})

		Describe("AddJob", func() {
			It("creates a service with vcap description", func() {
				Expect(AddJob()).ToNot(HaveOccurred())

				stdout, _, _, err := runner.RunCommand("powershell", "/C", "get-service", "say-hello-1")
				Expect(err).ToNot(HaveOccurred())
				Expect(stdout).To(ContainSubstring("say-hello-1"))
				Expect(stdout).To(ContainSubstring("Stopped"))

				for _, proc := range configContents.Processes {
					stdout, _, _, err := runner.RunCommand("powershell", "/C", "get-service", proc.Name)
					Expect(err).ToNot(HaveOccurred())
					Expect(stdout).To(ContainSubstring(proc.Name))
					Expect(stdout).To(ContainSubstring("Stopped"))
				}
			})

			Context("when monit file is empty", func() {
				BeforeEach(func() {
					err := fs.WriteFileString(processConfigPath, "")
					Expect(err).ToNot(HaveOccurred())
				})

				It("does not return an error", func() {
					Expect(AddJob()).ToNot(HaveOccurred())
				})
			})
		})

		Describe("Start", func() {
			BeforeEach(func() {
				Expect(AddJob()).ToNot(HaveOccurred())
			})

			It("will start all the services", func() {
				Expect(jobSupervisor.Start()).To(Succeed())

				for _, proc := range configContents.Processes {
					stdout, _, _, err := runner.RunCommand("powershell", "/C", "get-service", proc.Name)
					Expect(err).ToNot(HaveOccurred())
					Expect(stdout).To(ContainSubstring(proc.Name))
					Expect(stdout).To(ContainSubstring("Running"))
				}
			})

			It("writes logs to job log directory", func() {
				Expect(jobSupervisor.Start()).To(Succeed())

				for i, proc := range configContents.Processes {
					readLogFile := func() (string, error) {
						return fs.ReadFileString(path.Join(logDir, "say-hello", proc.Name, "job-service-wrapper.out.log"))
					}

					Eventually(readLogFile, 10*time.Second, 500*time.Millisecond).Should(ContainSubstring(fmt.Sprintf("Hello %d", i+1)))
				}
			})
		})

		Describe("Status", func() {
			Context("with jobs", func() {
				BeforeEach(func() {
					Expect(AddJob()).ToNot(HaveOccurred())
				})

				Context("when running", func() {
					It("reports that the job is 'Running'", func() {
						err := jobSupervisor.Start()
						Expect(err).ToNot(HaveOccurred())

						Expect(jobSupervisor.Status()).To(Equal("running"))
					})
				})

				Context("when stopped", func() {
					It("reports that the job is 'Stopped'", func() {
						err := jobSupervisor.Start()
						Expect(err).ToNot(HaveOccurred())

						err = jobSupervisor.Stop()
						Expect(err).ToNot(HaveOccurred())

						Expect(jobSupervisor.Status()).To(Equal("stopped"))
					})
				})
			})

			Context("with no jobs", func() {
				Context("when running", func() {
					It("reports that the job is 'Running'", func() {
						err := jobSupervisor.Start()
						Expect(err).ToNot(HaveOccurred())

						Expect(jobSupervisor.Status()).To(Equal("running"))
					})
				})
			})
		})

		Describe("Unmonitor", func() {
			BeforeEach(func() {
				Expect(AddJob()).ToNot(HaveOccurred())
			})

			It("sets service status to Disabled", func() {
				err := jobSupervisor.Unmonitor()
				Expect(err).ToNot(HaveOccurred())

				for _, proc := range configContents.Processes {
					stdout, _, _, err := runner.RunCommand(
						"powershell", "/C", "get-wmiobject", "win32_service", "-filter",
						fmt.Sprintf(`"name='%s'"`, proc.Name), "-property", "StartMode",
					)
					Expect(err).ToNot(HaveOccurred())
					Expect(stdout).To(ContainSubstring("Disabled"))
				}
			})
		})
	})

	Describe("WindowsProcess#ServiceWrapperConfig", func() {
		Context("when the WindowsProcess has environment variables", func() {
			It("adds them to the marshalled WindowsServiceWrapperConfig XML", func() {
				proc := WindowsProcess{
					Name:       "Name",
					Executable: "Executable",
					Args:       []string{"A", "B"},
					Env: map[string]string{
						"Key_1": "Val_1",
						"Key_2": "Val_2",
					},
				}
				srvc := proc.ServiceWrapperConfig("LogPath")
				Expect(len(srvc.Env)).To(Equal(len(proc.Env)))
				for _, e := range srvc.Env {
					Expect(e.Value).To(Equal(proc.Env[e.Name]))
				}
			})
		})
	})
})
<commit_msg>Use To(Succeed()) instead of NotTo(HaveOccurred()) on fns that only return an error<commit_after>package jobsupervisor_test

import (
	"encoding/json"
	"fmt"
	"os"
	"path"
	"path/filepath"
	"runtime"
	"time"

	boshdirs "github.com/cloudfoundry/bosh-agent/settings/directories"
	boshlog "github.com/cloudfoundry/bosh-utils/logger"
	boshsys "github.com/cloudfoundry/bosh-utils/system"

	. "github.com/cloudfoundry/bosh-agent/jobsupervisor"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("WindowsJobSupervisor", func() {
	Context("add jobs and control services", func() {
		BeforeEach(func() {
			if runtime.GOOS != "windows" {
				Skip("Pending on non-Windows")
			}
		})

		var (
			runner            boshsys.CmdRunner
			fs                boshsys.FileSystem
			jobSupervisor     JobSupervisor
			jobDir            string
			processConfigPath string
			basePath          string
			exePath           string
			logDir            string
			exePathNotExist   bool
			configContents    WindowsProcessConfig
		)

		AddJob := func() error {
			return jobSupervisor.AddJob("say-hello", 0, processConfigPath)
		}

		BeforeEach(func() {
			logger := boshlog.NewLogger(boshlog.LevelNone)
			fs = boshsys.NewOsFileSystem(logger)

			basePath = "C:/var/vcap/"
			fs.MkdirAll(basePath, 0755)

			binPath := filepath.Join(basePath, "bosh", "bin")
			fs.MkdirAll(binPath, 0755)

			logDir = path.Join(basePath, "sys", "log")
			fs.MkdirAll(binPath, 0755)

			const testExtPath = "testdata/job-service-wrapper"
			exePath = filepath.Join(binPath, "job-service-wrapper.exe")

			_, err := os.Stat(exePath)
			exePathNotExist = os.IsNotExist(err)
			if exePathNotExist {
				Expect(fs.CopyFile(testExtPath, exePath)).To(Succeed())
			}

			logDir = path.Join(basePath, "sys", "log")

			configContents = WindowsProcessConfig{
				Processes: []WindowsProcess{
					{
						Name:       fmt.Sprintf("say-hello-1-%d", time.Now().UnixNano()),
						Executable: "powershell",
						Args:       []string{"/C", "Write-Host \"Hello 1\"; Start-Sleep 10"},
					},
					{
						Name:       fmt.Sprintf("say-hello-2-%d", time.Now().UnixNano()),
						Executable: "powershell",
						Args:       []string{"/C", "Write-Host \"Hello 2\"; Start-Sleep 10"},
					},
				},
			}

			processConfigContents, err := json.Marshal(configContents)
			Expect(err).ToNot(HaveOccurred())

			dirProvider := boshdirs.NewProvider(basePath)

			runner = boshsys.NewExecCmdRunner(logger)
			jobSupervisor = NewWindowsJobSupervisor(runner, dirProvider, fs, logger)
			Expect(jobSupervisor.RemoveAllJobs()).To(Succeed())

			jobDir, err = fs.TempDir("testWindowsJobSupervisor")
			processConfigPath = filepath.Join(jobDir, "monit")

			Expect(fs.WriteFile(processConfigPath, processConfigContents)).To(Succeed())
		})

		AfterEach(func() {
			Expect(jobSupervisor.Stop()).To(Succeed())
			Expect(jobSupervisor.RemoveAllJobs()).To(Succeed())
			Expect(fs.RemoveAll(jobDir)).To(Succeed())
			Expect(fs.RemoveAll(logDir)).To(Succeed())
			if exePathNotExist {
				Expect(fs.RemoveAll(exePath)).To(Succeed())
			}
		})

		Describe("AddJob", func() {
			It("creates a service with vcap description", func() {
				Expect(AddJob()).To(Succeed())

				for _, proc := range configContents.Processes {
					stdout, _, _, err := runner.RunCommand("powershell", "/C", "get-service", proc.Name)
					Expect(err).ToNot(HaveOccurred())
					Expect(stdout).To(ContainSubstring(proc.Name))
					Expect(stdout).To(ContainSubstring("Stopped"))
				}
			})

			Context("when monit file is empty", func() {
				BeforeEach(func() {
					Expect(fs.WriteFileString(processConfigPath, "")).To(Succeed())
				})

				It("does not return an error", func() {
					Expect(AddJob()).To(Succeed())
				})
			})
		})

		Describe("Start", func() {
			BeforeEach(func() {
				Expect(AddJob()).To(Succeed())
			})

			It("will start all the services", func() {
				Expect(jobSupervisor.Start()).To(Succeed())

				for _, proc := range configContents.Processes {
					stdout, _, _, err := runner.RunCommand("powershell", "/C", "get-service", proc.Name)
					Expect(err).ToNot(HaveOccurred())
					Expect(stdout).To(ContainSubstring(proc.Name))
					Expect(stdout).To(ContainSubstring("Running"))
				}
			})

			It("writes logs to job log directory", func() {
				Expect(jobSupervisor.Start()).To(Succeed())

				for i, proc := range configContents.Processes {
					readLogFile := func() (string, error) {
						return fs.ReadFileString(path.Join(logDir, "say-hello", proc.Name, "job-service-wrapper.out.log"))
					}

					Eventually(readLogFile, 10*time.Second, 500*time.Millisecond).Should(ContainSubstring(fmt.Sprintf("Hello %d", i+1)))
				}
			})
		})

		Describe("Status", func() {
			Context("with jobs", func() {
				BeforeEach(func() {
					Expect(AddJob()).To(Succeed())
				})

				Context("when running", func() {
					It("reports that the job is 'Running'", func() {
						Expect(jobSupervisor.Start()).To(Succeed())

						Expect(jobSupervisor.Status()).To(Equal("running"))
					})
				})

				Context("when stopped", func() {
					It("reports that the job is 'Stopped'", func() {
						Expect(jobSupervisor.Start()).To(Succeed())

						Expect(jobSupervisor.Stop()).To(Succeed())

						Expect(jobSupervisor.Status()).To(Equal("stopped"))
					})
				})
			})

			Context("with no jobs", func() {
				Context("when running", func() {
					It("reports that the job is 'Running'", func() {
						Expect(jobSupervisor.Start()).To(Succeed())

						Expect(jobSupervisor.Status()).To(Equal("running"))
					})
				})
			})
		})

		Describe("Unmonitor", func() {
			BeforeEach(func() {
				Expect(AddJob()).To(Succeed())
			})

			It("sets service status to Disabled", func() {
				Expect(jobSupervisor.Unmonitor()).To(Succeed())

				for _, proc := range configContents.Processes {
					stdout, _, _, err := runner.RunCommand(
						"powershell", "/C", "get-wmiobject", "win32_service", "-filter",
						fmt.Sprintf(`"name='%s'"`, proc.Name), "-property", "StartMode",
					)
					Expect(err).ToNot(HaveOccurred())
					Expect(stdout).To(ContainSubstring("Disabled"))
				}
			})
		})
	})

	Describe("WindowsProcess#ServiceWrapperConfig", func() {
		Context("when the WindowsProcess has environment variables", func() {
			It("adds them to the marshalled WindowsServiceWrapperConfig XML", func() {
				proc := WindowsProcess{
					Name:       "Name",
					Executable: "Executable",
					Args:       []string{"A", "B"},
					Env: map[string]string{
						"Key_1": "Val_1",
						"Key_2": "Val_2",
					},
				}
				srvc := proc.ServiceWrapperConfig("LogPath")
				Expect(len(srvc.Env)).To(Equal(len(proc.Env)))
				for _, e := range srvc.Env {
					Expect(e.Value).To(Equal(proc.Env[e.Name]))
				}
			})
		})
	})
})
<|endoftext|>


<commit_before>package main

import (
	"log"
	"net/http"
	"github.com/rs/cors"
)

func listHandler(w http.ResponseWriter, req *http.Request) {
	w.Header().Set("Content-Type", "text/plain")
	w.Write([]byte("List requested.\n"))
}

func adminHandler(w http.ResponseWriter, req *http.Request) {
	w.Header().Set("Content-Type", "text/plain")
	w.Write([]byte("helo\n"))
}

func main() {
	mux := http.NewServeMux()
	mux.HandleFunc("/", listHandler)
	mux.HandleFunc("/list", listHandler)
	mux.HandleFunc("/admin", adminHandler)

	handler := cors.Default().Handler(mux)

	log.Printf("About to listen on 3001. Go to http://127.0.0.1:3001/")
	//err := http.ListenAndServeTLS(":3001", "cert.pem", "key.pem", nil)
	err := http.ListenAndServe(":3001", handler)
	log.Fatal(err)
}
<commit_msg>Allow DELETE. Implement POST and DELETE as add and delete from current speakerslist<commit_after>package main

import (
	"github.com/gorilla/context"
	"github.com/gorilla/sessions"
	"github.com/rs/cors"
	"encoding/json"
	"log"
	"net/http"
)

type State struct {
	Participators []sessions.Session   // All participators at the student division meeting.
	SpeakerLists  [][]sessions.Session // A list of speakerLists where each index is a list of sessions in queue to speak
}

var store = sessions.NewCookieStore([]byte("this is the secret stuff"))
var state State

func listHandler(w http.ResponseWriter, req *http.Request) {
	log.Print("Listhandler begin")
	session, err := store.Get(req, "talarlista_session")
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	if session.IsNew {
		state.Participators = append(state.Participators, *session)
	}

	session.Options = &sessions.Options{
		MaxAge:   86400,
		HttpOnly: true,
	}

	session.Save(req, w)

	w.Header().Set("Content-Type", "text/plain")
	w.Header().Set("Access-Control-Allow-Origin", "*")

	switch req.Method {
	case http.MethodGet:
		listGet(w, session)
	case http.MethodPost:
		listPost(w, session)
	case http.MethodDelete:
		listDelete(w, session)
	default:
		w.Write([]byte("List unsupported method.\n"))
		log.Print("Unsupported method")
	}
}

func listGet(w http.ResponseWriter, session *sessions.Session) {
	b, err := json.Marshal(state)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	w.Write(b)
}

func listPost(w http.ResponseWriter, session *sessions.Session) {
	w.Write([]byte("List post.\n"))
	session.Values["registered"] = true

	currentSpeakerList := state.SpeakerLists[len(state.SpeakerLists)-1]

	if isRegistered(session, currentSpeakerList) {
		http.Error(w, "Already registered", http.StatusUnprocessableEntity)
		return
	} else {
		state.SpeakerLists[len(state.SpeakerLists)-1] = append(currentSpeakerList, *session)
		w.Write([]byte("Added to speakerslist"))
	}
}

func listDelete(w http.ResponseWriter, session *sessions.Session) {
	session.Values["registered"] = false
	currentSpeakerList := state.SpeakerLists[len(state.SpeakerLists)-1]
	if isRegistered(session, currentSpeakerList) {
		state.SpeakerLists[len(state.SpeakerLists)-1] = removeSessionFromList(session, currentSpeakerList)
		w.Write([]byte("Removed from speakerslist\n"))
	} else {
		http.Error(w, "Not in list", http.StatusUnprocessableEntity)
		return
	}

	w.Write([]byte("List delete.\n"))
}

func isRegistered(currentSession *sessions.Session, speakersList []sessions.Session) bool {
	for _, session := range speakersList {
		if (*currentSession).ID == session.ID {
			return true
		}
	}
	return false
}

func removeSessionFromList(session *sessions.Session, sessionList []sessions.Session) []sessions.Session {
	sessionIndex := -1
	for i, s := range sessionList {
		if (*session).ID == s.ID {
			sessionIndex = i
			break
		}
	}

	if sessionIndex == -1 {
		return sessionList
	} else {
		return append(sessionList[:sessionIndex], sessionList[sessionIndex+1:]...)
	}
}

func adminHandler(w http.ResponseWriter, req *http.Request) {
	w.Header().Set("Content-Type", "text/plain")
	w.Write([]byte("helo\n"))
}

func main() {
	state.SpeakerLists = append(state.SpeakerLists, []sessions.Session{})

	mux := http.NewServeMux()
	mux.HandleFunc("/", listHandler)
	mux.HandleFunc("/list", listHandler)
	mux.HandleFunc("/admin", adminHandler)

	handler := cors.Default().Handler(mux)

	c := cors.New(cors.Options{
		//Debug: true,
		AllowedMethods: []string{"GET", "POST", "DELETE"},
	})
	handler = c.Handler(handler)

	handler = context.ClearHandler(handler)

	log.Printf("About to listen on 3001. Go to http://127.0.0.1:3001/")
	//err := http.ListenAndServeTLS(":3001", "cert.pem", "key.pem", nil)
	err := http.ListenAndServe(":3001", handler)
	log.Fatal(err)
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"os"
	"syscall"

	"net/http"

	"github.com/gorilla/mux"
	"github.com/op/go-logging"
)

var logger = logging.MustGetLogger("nomad-ui")

func init() {
	logBackend := logging.NewLogBackend(os.Stderr, "", 0)

	logBackendLeveled := logging.AddModuleLevel(logBackend)
	logBackendLeveled.SetLevel(logging.INFO, "")

	format := logging.MustStringFormatter(
		`%{color}%{time:15:04:05.000} %{shortfunc} ▶ %{level:.4s} %{color:reset} %{message}`,
	)
	backend2Formatter := logging.NewBackendFormatter(logBackendLeveled, format)

	logging.SetBackend(backend2Formatter)
}

type Config struct {
	Address       string
	ListenAddress string
}

func DefaultConfig() *Config {
	return &Config{
		Address:       "http://127.0.0.1:4646",
		ListenAddress: "0.0.0.0:3000",
	}
}

func flagDefault(value string) string {
	return fmt.Sprintf("(default: \"%s\")", value)
}

var (
	defaultConfig = DefaultConfig()

	flagAddress = flag.String("address", "", "The address of the Nomad server. "+
		"Overrides the NOMAD_ADDR environment variable if set. "+flagDefault(defaultConfig.Address))
	flagListenAddress = flag.String("web.listen-address", "",
		"The address on which to expose the web interface. "+flagDefault(defaultConfig.ListenAddress))
)

func (c *Config) Parse() {
	flag.Parse()

	address, ok := syscall.Getenv("NOMAD_ADDR")
	if ok {
		c.Address = address
	}
	if *flagAddress != "" {
		c.Address = *flagAddress
	}
	if *flagListenAddress != "" {
		c.ListenAddress = *flagListenAddress
	}
}

func main() {
	cfg := DefaultConfig()
	cfg.Parse()
	logger.Infof("----------------------------------------------------------------------")
	logger.Infof("|                          NOMAD UI                                  |")
	logger.Infof("----------------------------------------------------------------------")
	logger.Infof("| address            : %-45s |", cfg.Address)
	logger.Infof("| web.listen-address : %-45s |", cfg.ListenAddress)
	logger.Infof("----------------------------------------------------------------------")
	logger.Infof("")

	broadcast := make(chan *Action)

	logger.Infof("Connecting to nomad ...")
	nomad, err := NewNomad(cfg.Address, broadcast)
	if err != nil {
		logger.Fatalf("Could not create client: %s", err)
	}

	go nomad.watchAllocs()
	go nomad.watchEvals()
	go nomad.watchJobs()
	go nomad.watchNodes()
	go nomad.watchMembers()

	hub := NewHub(nomad, broadcast)
	go hub.Run()

	router := mux.NewRouter()
	router.HandleFunc("/ws", hub.Handler)
	router.PathPrefix("/").Handler(http.FileServer(assetFS()))

	logger.Infof("Listening ...")
	err = http.ListenAndServe(cfg.ListenAddress, router)
	if err != nil {
		logger.Fatal(err)
	}
}
<commit_msg>Fix logging.<commit_after>package main

import (
	"flag"
	"fmt"
	"os"
	"syscall"

	"net/http"

	"github.com/gorilla/mux"
	"github.com/op/go-logging"
)

var logger = logging.MustGetLogger("nomad-ui")

func init() {
	logBackend := logging.NewLogBackend(os.Stderr, "", 0)

	format := logging.MustStringFormatter(
		`%{color}%{time:15:04:05.000} %{shortfunc} ▶ %{level:.4s} %{color:reset} %{message}`,
	)
	logBackendFormatted := logging.NewBackendFormatter(logBackend, format)

	logBackendFormattedAndLeveled := logging.AddModuleLevel(logBackendFormatted)
	logBackendFormattedAndLeveled.SetLevel(logging.INFO, "")

	logging.SetBackend(logBackendFormattedAndLeveled)
}

type Config struct {
	Address       string
	ListenAddress string
}

func DefaultConfig() *Config {
	return &Config{
		Address:       "http://127.0.0.1:4646",
		ListenAddress: "0.0.0.0:3000",
	}
}

func flagDefault(value string) string {
	return fmt.Sprintf("(default: \"%s\")", value)
}

var (
	defaultConfig = DefaultConfig()

	flagAddress = flag.String("address", "", "The address of the Nomad server. "+
		"Overrides the NOMAD_ADDR environment variable if set. "+flagDefault(defaultConfig.Address))
	flagListenAddress = flag.String("web.listen-address", "",
		"The address on which to expose the web interface. "+flagDefault(defaultConfig.ListenAddress))
)

func (c *Config) Parse() {
	flag.Parse()

	address, ok := syscall.Getenv("NOMAD_ADDR")
	if ok {
		c.Address = address
	}
	if *flagAddress != "" {
		c.Address = *flagAddress
	}
	if *flagListenAddress != "" {
		c.ListenAddress = *flagListenAddress
	}
}

func main() {
	cfg := DefaultConfig()
	cfg.Parse()
	logger.Infof("----------------------------------------------------------------------")
	logger.Infof("|                          NOMAD UI                                  |")
	logger.Infof("----------------------------------------------------------------------")
	logger.Infof("| address            : %-45s |", cfg.Address)
	logger.Infof("| web.listen-address : %-45s |", cfg.ListenAddress)
	logger.Infof("----------------------------------------------------------------------")
	logger.Infof("")

	broadcast := make(chan *Action)

	logger.Infof("Connecting to nomad ...")
	nomad, err := NewNomad(cfg.Address, broadcast)
	if err != nil {
		logger.Fatalf("Could not create client: %s", err)
	}

	go nomad.watchAllocs()
	go nomad.watchEvals()
	go nomad.watchJobs()
	go nomad.watchNodes()
	go nomad.watchMembers()

	hub := NewHub(nomad, broadcast)
	go hub.Run()

	router := mux.NewRouter()
	router.HandleFunc("/ws", hub.Handler)
	router.PathPrefix("/").Handler(http.FileServer(assetFS()))

	logger.Infof("Listening ...")
	err = http.ListenAndServe(cfg.ListenAddress, router)
	if err != nil {
		logger.Fatal(err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"log"

	"github.com/tukdesk/tukdesk/backend/apis"
	"github.com/tukdesk/tukdesk/backend/config"
	"github.com/tukdesk/tukdesk/backend/models/helpers"

	"github.com/tukdesk/httputils/gojimiddleware"
	"github.com/tukdesk/mgoutils"
)

func main() {
	// config for dev
	cfg := config.Config{
		Addr: "127.0.0.1:52081",
		Database: config.DatabaseConfig{
			DBURL:  "127.0.0.1:27017",
			DBName: "tukdesk_dev",
		},
	}

	// init database storage
	stg, err := mgoutils.NewMgoPool(cfg.Database.DBURL, cfg.Database.DBName)
	if err != nil {
		log.Fatalln(err)
	}

	if err := helpers.InitWithStorage(stg); err != nil {
		log.Fatalln(err)
	}

	// init app
	app := gojimiddleware.NewApp()

	apis.RegisterBaseModule(cfg, app.Mux())
	apis.RegisterBrandModule(cfg, app.Mux())
	apis.RegisterProfileModule(cfg, app.Mux())
	apis.RegisterTicketsModule(cfg, app.Mux())
	apis.RegisterUserModule(cfg, app.Mux())
	apis.RegisterFocusModule(cfg, app.Mux())

	app.Mux().Use(gojimiddleware.RequestLogger)
	app.Mux().Use(gojimiddleware.RequestTimer)
	app.Mux().Use(gojimiddleware.RecovererJson)

	if err := app.Run(cfg.Addr); err != nil {
		log.Fatalln(err)
	}
}
<commit_msg>add api url prefix<commit_after>package main

import (
	"log"

	"github.com/tukdesk/tukdesk/backend/apis"
	"github.com/tukdesk/tukdesk/backend/config"
	"github.com/tukdesk/tukdesk/backend/models/helpers"

	"github.com/tukdesk/httputils/gojimiddleware"
	"github.com/tukdesk/mgoutils"
	"github.com/zenazn/goji/web"
)

func main() {
	// config for dev
	cfg := config.Config{
		Addr: "127.0.0.1:52081",
		Database: config.DatabaseConfig{
			DBURL:  "127.0.0.1:27017",
			DBName: "tukdesk_dev",
		},
	}

	// init database storage
	stg, err := mgoutils.NewMgoPool(cfg.Database.DBURL, cfg.Database.DBName)
	if err != nil {
		log.Fatalln(err)
	}

	if err := helpers.InitWithStorage(stg); err != nil {
		log.Fatalln(err)
	}

	// init app
	app := web.New()
	apis.RegisterBaseModule(cfg, app)
	apis.RegisterBrandModule(cfg, app)
	apis.RegisterProfileModule(cfg, app)
	apis.RegisterTicketsModule(cfg, app)
	apis.RegisterUserModule(cfg, app)
	apis.RegisterFocusModule(cfg, app)

	service := gojimiddleware.NewApp()
	service.Mux().Use(gojimiddleware.RequestLogger)
	service.Mux().Use(gojimiddleware.RequestTimer)
	service.Mux().Use(gojimiddleware.RecovererJson)

	gojimiddleware.RegisterSubroute("/apis/v1", service.Mux(), app)

	if err := service.Run(cfg.Addr); err != nil {
		log.Fatalln(err)
	}
}
<|endoftext|>


<commit_before>package extensions

import (
	"fmt"
	"math/rand"

	"github.com/gocolly/colly"
)

var uaGens = []func() string{
	genFirefoxUA,
	genChromeUA,
}

// RandomUserAgent generates a random browser user agent on every request
func RandomUserAgent(c *colly.Collector) {
	c.OnRequest(func(r *colly.Request) {
		r.Headers.Set("User-Agent", uaGens[rand.Intn(len(uaGens))]())
	})
}

var ffVersions = []float32{
	58.0,
	57.0,
	56.0,
	52.0,
	48.0,
	40.0,
	35.0,
}

var chromeVersions = []string{
	"65.0.3325.146",
	"64.0.3282.0",
	"41.0.2228.0",
	"40.0.2214.93",
	"37.0.2062.124",
}

var osStrings = []string{
	"Macintosh; Intel Mac OS X 10_10",
	"Windows NT 10.0",
	"Windows NT 5.1",
	"Windows NT 6.1; WOW64",
	"Windows NT 6.1; Win64; x64",
	"X11; Linux x86_64",
}

func genFirefoxUA() string {
	version := ffVersions[rand.Intn(len(ffVersions))]
	os := osStrings[rand.Intn(len(osStrings))]
	return fmt.Sprintf("Mozilla/5.0 (%s; rv:%.1f) Gecko/20100101 Firefox/%.1f", os, version, version)
}

func genChromeUA() string {
	version := chromeVersions[rand.Intn(len(chromeVersions))]
	os := osStrings[rand.Intn(len(osStrings))]
	return fmt.Sprintf("Mozilla/5.0 (%s) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/%s Safari/537.36", os, version)
}
<commit_msg>adds random user-agent for Opera<commit_after>package extensions

import (
	"fmt"
	"math/rand"

	"github.com/gocolly/colly"
)

var uaGens = []func() string{
	genFirefoxUA,
	genChromeUA,
	genOperaUA,
}

// RandomUserAgent generates a random browser user agent on every request
func RandomUserAgent(c *colly.Collector) {
	c.OnRequest(func(r *colly.Request) {
		r.Headers.Set("User-Agent", uaGens[rand.Intn(len(uaGens))]())
	})
}

var ffVersions = []float32{
	58.0,
	57.0,
	56.0,
	52.0,
	48.0,
	40.0,
	35.0,
}

var chromeVersions = []string{
	"65.0.3325.146",
	"64.0.3282.0",
	"41.0.2228.0",
	"40.0.2214.93",
	"37.0.2062.124",
}

var operaVersions = []string{
	"2.7.62 Version/11.00",
	"2.2.15 Version/10.10",
	"2.9.168 Version/11.50",
	"2.2.15 Version/10.00",
	"2.8.131 Version/11.11",
	"2.5.24 Version/10.54",
}

var osStrings = []string{
	"Macintosh; Intel Mac OS X 10_10",
	"Windows NT 10.0",
	"Windows NT 5.1",
	"Windows NT 6.1; WOW64",
	"Windows NT 6.1; Win64; x64",
	"X11; Linux x86_64",
}

func genFirefoxUA() string {
	version := ffVersions[rand.Intn(len(ffVersions))]
	os := osStrings[rand.Intn(len(osStrings))]
	return fmt.Sprintf("Mozilla/5.0 (%s; rv:%.1f) Gecko/20100101 Firefox/%.1f", os, version, version)
}

func genChromeUA() string {
	version := chromeVersions[rand.Intn(len(chromeVersions))]
	os := osStrings[rand.Intn(len(osStrings))]
	return fmt.Sprintf("Mozilla/5.0 (%s) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/%s Safari/537.36", os, version)
}

func genOperaUA() string {
	version := operaVersions[rand.Intn(len(operaVersions))]
	os := osStrings[rand.Intn(len(osStrings))]
	return fmt.Sprintf("Opera/9.80 (%s; U; en) Presto/%s", os, version)
}
<|endoftext|>


<commit_before>package main

import "testing"

func TestConfigUpdate(t *testing.T) {
	c := ConfigNew()

	origApiKey := c.APIKey
	newApiKey := "newkey"

	if err := c.Update(newApiKey); err != nil {
		t.Fatal(err)
	}

	c.Load()

	if c.APIKey != newApiKey {
		t.Fail()
	}

	if err := c.Update(origApiKey); err != nil {
		t.Fatal(err)
	}
}
<commit_msg>Replace APIKey with Token<commit_after>package main

import "testing"

func TestConfigUpdate(t *testing.T) {
	c := ConfigNew()

	origApiKey := c.Token
	newApiKey := "newkey"

	if err := c.Update(newApiKey); err != nil {
		t.Fatal(err)
	}

	c.Load()

	if c.Token != newApiKey {
		t.Fail()
	}

	if err := c.Update(origApiKey); err != nil {
		t.Fatal(err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"testing"

	. "github.com/aandryashin/matchers"
)

func TestEmptyListOfHosts(t *testing.T) {
	host, index := Hosts{}.choose()
	AssertThat(t, host, Is{(*Host)(nil)})
	AssertThat(t, index, EqualTo{-1})
}

func TestNothingToChoose(t *testing.T) {
	host, index := Hosts{Host{Count: 0}, Host{Count: 0}}.choose()
	AssertThat(t, host, Is{(*Host)(nil)})
	AssertThat(t, index, EqualTo{-1})
}

func TestChooseFirst(t *testing.T) {
	host, index := Hosts{Host{Name: "first", Count: 2}, Host{Name: "mid", Count: 1}, Host{Name: "last", Count: 1}}.choose()
	AssertThat(t, host.Name, EqualTo{"first"})
	AssertThat(t, index, EqualTo{0})
}

func TestChooseMid(t *testing.T) {
	host, index := Hosts{Host{Name: "first", Count: 1}, Host{Name: "mid", Count: 2}, Host{Name: "last", Count: 1}}.choose()
	AssertThat(t, host.Name, EqualTo{"mid"})
	AssertThat(t, index, EqualTo{1})
}

func TestChooseLast(t *testing.T) {
	host, index := Hosts{Host{Name: "first", Count: 1}, Host{Name: "mid", Count: 1}, Host{Name: "last", Count: 2}}.choose()
	AssertThat(t, host.Name, EqualTo{"last"})
	AssertThat(t, index, EqualTo{2})
}
<commit_msg>Find host tests.<commit_after>package main

import (
	"testing"

	. "github.com/aandryashin/matchers"
)

func TestEmptyListOfHosts(t *testing.T) {
	host, index := Hosts{}.choose()
	AssertThat(t, host, Is{(*Host)(nil)})
	AssertThat(t, index, EqualTo{-1})
}

func TestNothingToChoose(t *testing.T) {
	host, index := Hosts{Host{Count: 0}, Host{Count: 0}}.choose()
	AssertThat(t, host, Is{(*Host)(nil)})
	AssertThat(t, index, EqualTo{-1})
}

func TestChooseFirst(t *testing.T) {
	host, index := Hosts{Host{Name: "first", Count: 2}, Host{Name: "mid", Count: 1}, Host{Name: "last", Count: 1}}.choose()
	AssertThat(t, host.Name, EqualTo{"first"})
	AssertThat(t, index, EqualTo{0})
}

func TestChooseMid(t *testing.T) {
	host, index := Hosts{Host{Name: "first", Count: 1}, Host{Name: "mid", Count: 2}, Host{Name: "last", Count: 1}}.choose()
	AssertThat(t, host.Name, EqualTo{"mid"})
	AssertThat(t, index, EqualTo{1})
}

func TestChooseLast(t *testing.T) {
	host, index := Hosts{Host{Name: "first", Count: 1}, Host{Name: "mid", Count: 1}, Host{Name: "last", Count: 2}}.choose()
	AssertThat(t, host.Name, EqualTo{"last"})
	AssertThat(t, index, EqualTo{2})
}

func TestFindDefaultVersion(t *testing.T) {
	hosts := (&Browsers{Browsers: []Browser{
		Browser{Name: "browser", DefaultVersion: "1.0", Versions: []Version{
			Version{Number: "1.0", Regions: []Region{
				Region{Hosts: Hosts{
					Host{Name: "browser-1.0"},
				}},
			}},
			Version{Number: "", Regions: []Region{
				Region{Hosts: Hosts{
					Host{Name: "browser"},
				}},
			}},
		}}}}).find("browser", "")
	AssertThat(t, len(hosts), EqualTo{1})
	AssertThat(t, hosts[0].Name, EqualTo{"browser-1.0"})
}

func TestFindVersion(t *testing.T) {
	hosts := (&Browsers{Browsers: []Browser{
		Browser{Name: "browser", DefaultVersion: "2.0", Versions: []Version{
			Version{Number: "2.0", Regions: []Region{
				Region{Hosts: Hosts{
					Host{Name: "browser-2.0"},
				}},
			}},
			Version{Number: "1.0", Regions: []Region{
				Region{Hosts: Hosts{
					Host{Name: "browser-1.0"},
				}},
			}},
		}}}}).find("browser", "1.0")
	AssertThat(t, len(hosts), EqualTo{1})
	AssertThat(t, hosts[0].Name, EqualTo{"browser-1.0"})
}

func TestVersionNotFound(t *testing.T) {
	hosts := (&Browsers{Browsers: []Browser{
		Browser{Name: "browser", DefaultVersion: "2.0", Versions: []Version{
			Version{Number: "2.0", Regions: []Region{
				Region{Hosts: Hosts{
					Host{Name: "browser-2.0"},
				}},
			}},
		}}}}).find("browser", "1.0")
	AssertThat(t, len(hosts), EqualTo{0})
}

func TestFindWithExcludes(t *testing.T) {
	hosts := (&Browsers{Browsers: []Browser{
		Browser{Name: "browser", DefaultVersion: "1.0", Versions: []Version{
			Version{Number: "1.0", Regions: []Region{
				Region{Name: "e", Hosts: Hosts{
					Host{Name: "browser-e-1.0"},
				}},
				Region{Name: "f", Hosts: Hosts{
					Host{Name: "browser-f-1.0"},
				}},
			}},
		}}}}).find("browser", "1.0", "f")
	AssertThat(t, len(hosts), EqualTo{1})
	AssertThat(t, hosts[0].Name, EqualTo{"browser-e-1.0"})
}
<|endoftext|>


<commit_before>//go:generate go run maketables.go > tables.go

package confusables

import (
	"unicode/utf8"

	"golang.org/x/text/unicode/norm"
)

// TODO: document casefolding approaches
// (suggest to force casefold strings; explain how to catch paypal - pAypal)
// TODO: implement tables other than MA
// (is it secure, even if overprocessing, to check only against MA?)
// TODO: DOC you might want to store the Skeleton and check against it later
// TODO: implement xidmodifications.txt restricted characters

// Skeleton converts a string to it's "skeleton" form
// as descibed in http://www.unicode.org/reports/tr39/#Confusable_Detection
func Skeleton(s string) string {

	// 1. Converting X to NFD format
	s = norm.NFD.String(s)

	// 2. Successively mapping each source character in X to the target string
	// according to the specified data table
	for i, w := 0, 0; i < len(s); i += w {
		char, width := utf8.DecodeRuneInString(s[i:])
		replacement, exists := confusablesMap[char]
		if exists {
			s = s[:i] + replacement + s[i+width:]
			w = len(replacement)
		} else {
			w = width
		}
	}

	// 3. Reapplying NFD
	s = norm.NFD.String(s)

	return s
}

func Confusable(x, y string) bool {
	return Skeleton(x) == Skeleton(y)
}
<commit_msg>remove obsolete todo<commit_after>//go:generate go run maketables.go > tables.go

package confusables

import (
	"unicode/utf8"

	"golang.org/x/text/unicode/norm"
)

// TODO: document casefolding approaches
// (suggest to force casefold strings; explain how to catch paypal - pAypal)
// TODO: DOC you might want to store the Skeleton and check against it later
// TODO: implement xidmodifications.txt restricted characters

// Skeleton converts a string to it's "skeleton" form
// as descibed in http://www.unicode.org/reports/tr39/#Confusable_Detection
func Skeleton(s string) string {

	// 1. Converting X to NFD format
	s = norm.NFD.String(s)

	// 2. Successively mapping each source character in X to the target string
	// according to the specified data table
	for i, w := 0, 0; i < len(s); i += w {
		char, width := utf8.DecodeRuneInString(s[i:])
		replacement, exists := confusablesMap[char]
		if exists {
			s = s[:i] + replacement + s[i+width:]
			w = len(replacement)
		} else {
			w = width
		}
	}

	// 3. Reapplying NFD
	s = norm.NFD.String(s)

	return s
}

func Confusable(x, y string) bool {
	return Skeleton(x) == Skeleton(y)
}
<|endoftext|>


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

// This file defines miscellaneous structs and utility methods that are used
// throughout the system.

package doctor

import (
	"fmt"
)

// An OffsetLength consists of two integers: a 0-based offset and a nonnegative
// length.  An OffsetLength is used to specify a region of a string or file.
// For example, given the string "ABCDEFG", the substring CDE could be
// specified by
//     OffsetLength{offset: 2, length: 3}
type OffsetLength struct {
	Offset int `json:"offset"`
	Length int `json:"length"`
}

func (o *OffsetLength) OffsetPastEnd() int {
	return o.Offset + o.Length
}

func (o *OffsetLength) String() string {
	return fmt.Sprintf("offset %d, length %d", o.Offset, o.Length)
}

// A TextSelection represents a selection in a text editor.  It consists of a
// filename, the line/column where the selected text begins, and the
// line/column where the text selection ends.  The end line and column must be
// greater than or equal to the start line and column, respectively.  Line and
// column numbers are 1-based.
type TextSelection struct {
	Filename  string
	StartLine int
	StartCol  int
	EndLine   int
	EndCol    int
}

func (s *TextSelection) String() string {
	return fmt.Sprintf("%s:%d,%d:%d,%d",
		s.Filename, s.StartLine, s.StartCol, s.EndLine, s.EndCol)
}

func (s *TextSelection) ShortString() string {
	return fmt.Sprintf("%d,%d:%d,%d",
		s.StartLine, s.StartCol, s.EndLine, s.EndCol)
}
<commit_msg>Updated comments in util.go<commit_after>// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This file defines miscellaneous structs and utility methods that are used
// throughout the system.

package doctor

import (
	"fmt"
)

// An OffsetLength consists of two integers: a 0-based byte offset and a
// nonnegative length.  An OffsetLength is used to specify a region of a string
// or file.  For example, given the string "ABCDEFG", the substring CDE could
// be specified by OffsetLength{offset: 2, length: 3}.
type OffsetLength struct {
	// Byte offset of the first character (0-based)
	Offset int `json:"offset"`
	// Length in bytes (nonnegative)
	Length int `json:"length"`
}

// OffsetPastEnd returns the offset of the first byte immediately beyond the
// end of this region.  For example, a region at offset 2 with length 3
// occupies bytes 2 through 4, so this method would return 5.
func (o *OffsetLength) OffsetPastEnd() int {
	return o.Offset + o.Length
}

func (o *OffsetLength) String() string {
	return fmt.Sprintf("offset %d, length %d", o.Offset, o.Length)
}

// A TextSelection represents a selection in a text editor.  It consists of a
// filename, the line/column where the selected text begins, and the
// line/column where the text selection ends.  The end line and column must be
// greater than or equal to the start line and column, respectively.  Line and
// column numbers are 1-based.
type TextSelection struct {
	Filename  string
	StartLine int
	StartCol  int
	EndLine   int
	EndCol    int
}

func (s *TextSelection) String() string {
	return fmt.Sprintf("%s:%d,%d:%d,%d",
		s.Filename, s.StartLine, s.StartCol, s.EndLine, s.EndCol)
}

func (s *TextSelection) ShortString() string {
	return fmt.Sprintf("%d,%d:%d,%d",
		s.StartLine, s.StartCol, s.EndLine, s.EndCol)
}
<|endoftext|>


<commit_before>package hstspreload

import (
	"fmt"
	"testing"
)

func ExamplePreloadableDomain() {
	header, issues := PreloadableDomain("wikipedia.org")
	if header != nil {
		fmt.Printf("Header: %s", *header)
	}
	fmt.Printf("Issues %v", issues)
}

/******** Utility functions tests. ********/

var testCheckDomainFormatTests = []struct {
	actual   Issues
	expected Issues
}{
	{checkDomainFormat(".example.com"),
		Issues{Errors: []Issue{Issue{Code: "domain.format.begins_with_dot"}}},
	},
	{checkDomainFormat("example.com."),
		Issues{Errors: []Issue{Issue{Code: "domain.format.ends_with_dot"}}},
	},
	{checkDomainFormat("example..com"),
		Issues{Errors: []Issue{Issue{Code: "domain.format.contains_double_dot"}}},
	},
	{checkDomainFormat("example"),
		Issues{Errors: []Issue{Issue{Code: "domain.format.only_one_label"}}},
	},
	{checkDomainFormat("example&co.com"),
		Issues{Errors: []Issue{Issue{Code: "domain.format.invalid_characters"}}},
	},
}

func TestCheckDomainFormat(t *testing.T) {
	for _, tt := range testCheckDomainFormatTests {
		if !issuesMatchExpected(tt.actual, tt.expected) {
			t.Errorf(issuesShouldMatch, tt.actual, tt.expected)
		}
	}
}

var testPreloadableDomainLevel = []struct {
	actual   Issues
	expected Issues
}{
	{preloadableDomainLevel("subdomain.example.com"),
		Issues{Errors: []Issue{Issue{
			Code:    "domain.is_subdomain",
			Message: "`subdomain.example.com` is a subdomain. Please preload `example.com` instead. (Due to the size of the preload list and the behaviour of cookies across subdomains, we only accept automated preload list submissions of whole registered domains.)",
		}}},
	},
}

func TestPreloadableDomainLevel(t *testing.T) {
	for _, tt := range testPreloadableDomainLevel {
		if !issuesMatchExpected(tt.actual, tt.expected) {
			t.Errorf(issuesShouldMatch, tt.actual, tt.expected)
		}
	}
}

/******** Real domain tests. ********/

// Avoid hitting the network for short tests.
// This gives us performant, deterministic, and offline testing.
func skipIfShort(t *testing.T) {
	if testing.Short() {
		t.Skip("Skipping domain test.")
	}
}

var preloadableDomainTests = []struct {
	function       func(domain string) (*string, Issues)
	description    string
	domain         string
	expectHeader   bool
	expectedHeader string
	expectedIssues Issues
}{

	/********* PreloadableDomain() ********/

	{
		PreloadableDomain,
		"valid HSTS",
		"wikipedia.org",
		true, "max-age=31536000; includeSubDomains; preload",
		Issues{},
	},
	{
		PreloadableDomain,
		"incomplete chain",
		"incomplete-chain.badssl.com",
		false, "",
		Issues{
			Errors: []Issue{
				Issue{Code: "domain.is_subdomain"},
				Issue{
					Code:    "domain.tls.cannot_connect",
					Message: "We cannot connect to https://incomplete-chain.badssl.com using TLS (\"Get https://incomplete-chain.badssl.com: x509: certificate signed by unknown authority\"). This might be caused by an incomplete certificate chain, which causes issues on mobile devices. Check out your site at https://www.ssllabs.com/ssltest/",
				},
			},
		},
	},
	{
		PreloadableDomain,
		"SHA-1",
		"sha1.badssl.com",
		false, "",
		Issues{
			Errors: []Issue{
				Issue{Code: "domain.is_subdomain"},
				Issue{
					Code:    "domain.tls.sha1",
					Message: "One or more of the certificates in your certificate chain is signed using SHA-1. This needs to be replaced. See https://security.googleblog.com/2015/12/an-update-on-sha-1-certificates-in.html. (The first SHA-1 certificate found has a common-name of \"*.badssl.com\".)",
				},
				Issue{Code: "response.no_header"},
			},
		},
	},
	{
		PreloadableDomain,
		"subdomain",
		"en.wikipedia.org",
		true, "max-age=31536000; includeSubDomains; preload",
		Issues{Errors: []Issue{Issue{
			Code:    "domain.is_subdomain",
			Message: "`en.wikipedia.org` is a subdomain. Please preload `wikipedia.org` instead. (Due to the size of the preload list and the behaviour of cookies across subdomains, we only accept automated preload list submissions of whole registered domains.)",
		}}},
	},
	{
		PreloadableDomain,
		"no HSTS",
		"example.com",
		false, "",
		Issues{
			Errors: []Issue{
				Issue{Code: "response.no_header"},
				Issue{
					Code:    "redirects.http.no_redirect",
					Message: "`http://example.com` does not redirect to `https://example.com`.",
				},
			},
		},
	},
	// Don't run this test like normal. See TestPreloadableDomainBogusDomain().
	{
		PreloadableDomain,
		"bogus domain",
		"example.notadomain",
		false, "",
		Issues{Errors: []Issue{Issue{Code: "domain.tls.cannot_connect"}}},
	},

	/******** RemovableDomain() ********/

	{
		RemovableDomain,
		"no header",
		"example.com",
		false, "",
		Issues{Errors: []Issue{Issue{Code: "response.no_header"}}},
	},
	{
		RemovableDomain,
		"no preload directive",
		"hsts.badssl.com",
		true, "max-age=15768000; includeSubDomains",
		Issues{},
	},
	{
		RemovableDomain,
		"preloaded",
		"preloaded-hsts.badssl.com",
		true, "max-age=15768000; includeSubDomains; preload",
		Issues{Errors: []Issue{Issue{Code: "header.removable.contains.preload"}}},
	},
}

func TestPreloadableDomainAndRemovableDomain(t *testing.T) {
	skipIfShort(t)

	for _, tt := range preloadableDomainTests {
		header, issues := tt.function(tt.domain)

		if tt.expectHeader {
			if header == nil {
				t.Errorf("[%s] %s: Did not receive exactly one HSTS header", tt.description, tt.domain)
			} else if *header != tt.expectedHeader {
				t.Errorf("[%s] %s: "+headerStringsShouldBeEqual, tt.description, tt.domain, *header, tt.expectedHeader)
			}
		} else {
			if header != nil {
				t.Errorf("[%s] %s: Did not expect a header, but received `%s`", tt.description, tt.domain, *header)
			}
		}

		if !issuesMatchExpected(issues, tt.expectedIssues) {
			t.Errorf("[%s] %s: "+issuesShouldMatch, tt.description, tt.domain, issues, tt.expectedIssues)
		}
	}
}

// func TestPreloadableDomainBogusDomain(t *testing.T) {
// 	skipIfShort(t)

// 	// The error message contains a local IP in Travis CI. Since this is the only
// 	// such test, we work around it with more crude checks.
// 	header, issues := PreloadableDomain("example.notadomain")
// 	if header != nil {
// 		t.Errorf("Did not expect a header, but received `%s`", *header)
// 	}
// 	if len(issues.Errors) != 1 || len(issues.Warnings) != 0 {
// 		t.Errorf("Expected one error and no warnings.")
// 	}
// 	if !strings.HasPrefix(issues.Errors[0], "TLS Error: We cannot connect to https://example.notadomain using TLS (\"Get https://example.notadomain: dial tcp: lookup example.notadomain") {
// 		t.Errorf("Expected one issues.")
// 	}
// 	if !strings.HasSuffix(issues.Errors[0], "no such host\"). This might be caused by an incomplete certificate chain, which causes issues on mobile devices. Check out your site at https://www.ssllabs.com/ssltest/") {
// 		t.Errorf("Expected one issues.")
// 	}
// }
<commit_msg>Change domain format test tables to contain input domains.<commit_after>package hstspreload

import (
	"fmt"
	"testing"
)

func ExamplePreloadableDomain() {
	header, issues := PreloadableDomain("wikipedia.org")
	if header != nil {
		fmt.Printf("Header: %s", *header)
	}
	fmt.Printf("Issues %v", issues)
}

/******** Utility functions tests. ********/

var testCheckDomainFormatTests = []struct {
	domain   string
	expected Issues
}{
	{".example.com",
		Issues{Errors: []Issue{Issue{Code: "domain.format.begins_with_dot"}}},
	},
	{"example.com.",
		Issues{Errors: []Issue{Issue{Code: "domain.format.ends_with_dot"}}},
	},
	{"example..com",
		Issues{Errors: []Issue{Issue{Code: "domain.format.contains_double_dot"}}},
	},
	{"example",
		Issues{Errors: []Issue{Issue{Code: "domain.format.only_one_label"}}},
	},
	{"example&co.com",
		Issues{Errors: []Issue{Issue{Code: "domain.format.invalid_characters"}}},
	},
}

func TestCheckDomainFormat(t *testing.T) {
	for _, tt := range testCheckDomainFormatTests {
		issues := checkDomainFormat(tt.domain)
		if !issuesMatchExpected(issues, tt.expected) {
			t.Errorf(issuesShouldMatch, issues, tt.expected)
		}
	}
}

var testPreloadableDomainLevel = []struct {
	domain   string
	expected Issues
}{
	{"subdomain.example.com",
		Issues{Errors: []Issue{Issue{
			Code:    "domain.is_subdomain",
			Message: "`subdomain.example.com` is a subdomain. Please preload `example.com` instead. (Due to the size of the preload list and the behaviour of cookies across subdomains, we only accept automated preload list submissions of whole registered domains.)",
		}}},
	},
}

func TestPreloadableDomainLevel(t *testing.T) {
	for _, tt := range testPreloadableDomainLevel {
		issues := preloadableDomainLevel(tt.domain)
		if !issuesMatchExpected(issues, tt.expected) {
			t.Errorf(issuesShouldMatch, issues, tt.expected)
		}
	}
}

/******** Real domain tests. ********/

// Avoid hitting the network for short tests.
// This gives us performant, deterministic, and offline testing.
func skipIfShort(t *testing.T) {
	if testing.Short() {
		t.Skip("Skipping domain test.")
	}
}

var preloadableDomainTests = []struct {
	function       func(domain string) (*string, Issues)
	description    string
	domain         string
	expectHeader   bool
	expectedHeader string
	expectedIssues Issues
}{

	/********* PreloadableDomain() ********/

	{
		PreloadableDomain,
		"valid HSTS",
		"wikipedia.org",
		true, "max-age=31536000; includeSubDomains; preload",
		Issues{},
	},
	{
		PreloadableDomain,
		"incomplete chain",
		"incomplete-chain.badssl.com",
		false, "",
		Issues{
			Errors: []Issue{
				Issue{Code: "domain.is_subdomain"},
				Issue{
					Code:    "domain.tls.cannot_connect",
					Message: "We cannot connect to https://incomplete-chain.badssl.com using TLS (\"Get https://incomplete-chain.badssl.com: x509: certificate signed by unknown authority\"). This might be caused by an incomplete certificate chain, which causes issues on mobile devices. Check out your site at https://www.ssllabs.com/ssltest/",
				},
			},
		},
	},
	{
		PreloadableDomain,
		"SHA-1",
		"sha1.badssl.com",
		false, "",
		Issues{
			Errors: []Issue{
				Issue{Code: "domain.is_subdomain"},
				Issue{
					Code:    "domain.tls.sha1",
					Message: "One or more of the certificates in your certificate chain is signed using SHA-1. This needs to be replaced. See https://security.googleblog.com/2015/12/an-update-on-sha-1-certificates-in.html. (The first SHA-1 certificate found has a common-name of \"*.badssl.com\".)",
				},
				Issue{Code: "response.no_header"},
			},
		},
	},
	{
		PreloadableDomain,
		"subdomain",
		"en.wikipedia.org",
		true, "max-age=31536000; includeSubDomains; preload",
		Issues{Errors: []Issue{Issue{
			Code:    "domain.is_subdomain",
			Message: "`en.wikipedia.org` is a subdomain. Please preload `wikipedia.org` instead. (Due to the size of the preload list and the behaviour of cookies across subdomains, we only accept automated preload list submissions of whole registered domains.)",
		}}},
	},
	{
		PreloadableDomain,
		"no HSTS",
		"example.com",
		false, "",
		Issues{
			Errors: []Issue{
				Issue{Code: "response.no_header"},
				Issue{
					Code:    "redirects.http.no_redirect",
					Message: "`http://example.com` does not redirect to `https://example.com`.",
				},
			},
		},
	},
	// Don't run this test like normal. See TestPreloadableDomainBogusDomain().
	{
		PreloadableDomain,
		"bogus domain",
		"example.notadomain",
		false, "",
		Issues{Errors: []Issue{Issue{Code: "domain.tls.cannot_connect"}}},
	},

	/******** RemovableDomain() ********/

	{
		RemovableDomain,
		"no header",
		"example.com",
		false, "",
		Issues{Errors: []Issue{Issue{Code: "response.no_header"}}},
	},
	{
		RemovableDomain,
		"no preload directive",
		"hsts.badssl.com",
		true, "max-age=15768000; includeSubDomains",
		Issues{},
	},
	{
		RemovableDomain,
		"preloaded",
		"preloaded-hsts.badssl.com",
		true, "max-age=15768000; includeSubDomains; preload",
		Issues{Errors: []Issue{Issue{Code: "header.removable.contains.preload"}}},
	},
}

func TestPreloadableDomainAndRemovableDomain(t *testing.T) {
	skipIfShort(t)

	for _, tt := range preloadableDomainTests {
		header, issues := tt.function(tt.domain)

		if tt.expectHeader {
			if header == nil {
				t.Errorf("[%s] %s: Did not receive exactly one HSTS header", tt.description, tt.domain)
			} else if *header != tt.expectedHeader {
				t.Errorf("[%s] %s: "+headerStringsShouldBeEqual, tt.description, tt.domain, *header, tt.expectedHeader)
			}
		} else {
			if header != nil {
				t.Errorf("[%s] %s: Did not expect a header, but received `%s`", tt.description, tt.domain, *header)
			}
		}

		if !issuesMatchExpected(issues, tt.expectedIssues) {
			t.Errorf("[%s] %s: "+issuesShouldMatch, tt.description, tt.domain, issues, tt.expectedIssues)
		}
	}
}

// func TestPreloadableDomainBogusDomain(t *testing.T) {
// 	skipIfShort(t)

// 	// The error message contains a local IP in Travis CI. Since this is the only
// 	// such test, we work around it with more crude checks.
// 	header, issues := PreloadableDomain("example.notadomain")
// 	if header != nil {
// 		t.Errorf("Did not expect a header, but received `%s`", *header)
// 	}
// 	if len(issues.Errors) != 1 || len(issues.Warnings) != 0 {
// 		t.Errorf("Expected one error and no warnings.")
// 	}
// 	if !strings.HasPrefix(issues.Errors[0], "TLS Error: We cannot connect to https://example.notadomain using TLS (\"Get https://example.notadomain: dial tcp: lookup example.notadomain") {
// 		t.Errorf("Expected one issues.")
// 	}
// 	if !strings.HasSuffix(issues.Errors[0], "no such host\"). This might be caused by an incomplete certificate chain, which causes issues on mobile devices. Check out your site at https://www.ssllabs.com/ssltest/") {
// 		t.Errorf("Expected one issues.")
// 	}
// }
<|endoftext|>