<commit_before>// +build linux

package main

import (
	"encoding/hex"
	"encoding/json"
	"io/ioutil"
	"log"
	"log/syslog"
	"os"
	"strings"

	"github.com/godbus/dbus"
	"gopkg.in/yaml.v1"
)

var conn *dbus.Conn

type State struct {
	Version string `json:"version"`
	ID      string `json:"id"`
	Pid     int    `json:"pid"`
	Root    string `json:"root"`
}

func Validate(id string) (string, error) {
	for len(id) < 32 {
		id += "0"
	}
	return hex.EncodeToString([]byte(id)), nil
}

// RegisterMachine with systemd on the host system
func RegisterMachine(name string, id string, pid int, root_directory string) error {
	var (
		av  []byte
		err error
	)
	if conn == nil {
		conn, err = dbus.SystemBus()
		if err != nil {
			return err
		}
	}

	av, err = hex.DecodeString(id[0:32])
	if err != nil {
		return err
	}
	obj := conn.Object("org.freedesktop.machine1", "/org/freedesktop/machine1")
	service := os.Getenv("container")
	if service == "" {
		service = "runc"
	}
	return obj.Call("org.freedesktop.machine1.Manager.RegisterMachine", 0, name[0:32], av, service, "container", uint32(pid), root_directory).Err
}

// TerminateMachine registered with systemd on the host system
func TerminateMachine(name string) error {
	var err error
	if conn == nil {
		conn, err = dbus.SystemBus()
		if err != nil {
			return err
		}
	}
	obj := conn.Object("org.freedesktop.machine1", "/org/freedesktop/machine1")
	return obj.Call("org.freedesktop.machine1.Manager.TerminateMachine", 0, name).Err
}

const CONFIG = "/etc/oci-register-machine.conf"

var settings struct {
	Disabled bool `yaml:"disabled"`
}

func main() {
	var state State

	logwriter, err := syslog.New(syslog.LOG_NOTICE, "oci-register-machine")
	if err == nil {
		log.SetOutput(logwriter)
	}
	// then config file settings

	data, err := ioutil.ReadFile(CONFIG)
	if err != nil {
		if !os.IsNotExist(err) {
			log.Fatalf("RegisterMachine Failed to read %s %v", CONFIG, err.Error())
		}
	} else {
		if err := yaml.Unmarshal(data, &settings); err != nil {
			log.Fatalf("RegisterMachine Failed to parse %s %v", CONFIG, err.Error())
		}
		if settings.Disabled {
			return
		}
	}

	if err := json.NewDecoder(os.Stdin).Decode(&state); err != nil {
		log.Fatalf("RegisterMachine Failed %v", err.Error())
	}

	command := map[bool]string{true: "prestart", false: "poststop"}[state.Pid > 0]
	if len(os.Args) > 1 {
		command = os.Args[1]
	}

	log.Printf("Register machine: %s %s %d %s", command, state.ID, state.Pid, state.Root)
	// ensure id is a hex string at least 32 chars
	passId, err := Validate(state.ID)
	if err != nil {
		log.Fatalf("RegisterMachine Failed %v", err.Error())
	}

	switch command {
	case "prestart":
		{
			if err = RegisterMachine(state.ID, passId, int(state.Pid), state.Root); err != nil {
				log.Fatalf("Register machine failed: %v", err)
			}
			return
		}
	case "poststop":
		{
			if err := TerminateMachine(state.ID); err != nil {
				if !strings.Contains(err.Error(), "No machine") {
					log.Fatalf("TerminateMachine failed: %v", err)
				}
			}
			return
		}
		log.Fatalf("Invalid command %q must be prestart|poststop", command)
	}
}
<commit_msg>oci-register-machine: support container_uuid environment variable<commit_after>// +build linux

package main

import (
	"encoding/hex"
	"encoding/json"
	"io/ioutil"
	"log"
	"log/syslog"
	"os"
	"strings"
	"fmt"

	"github.com/godbus/dbus"
	"gopkg.in/yaml.v1"
)

var conn *dbus.Conn

type State struct {
	Version    string `json:"version"`
	ID         string `json:"id"`
	Pid        int    `json:"pid"`
	Root       string `json:"root"`
	BundlePath string `json:"bundlePath"`
}

type Process struct {
	Env     []string       `json:"env"`
}

type Config struct {
	Process    *Process `json:"process"`
}

func Validate(id string) (string, error) {
	for len(id) < 32 {
		id += "0"
	}
	return hex.EncodeToString([]byte(id)), nil
}

// RegisterMachine with systemd on the host system
func RegisterMachine(name string, id string, pid int, root_directory string) error {
	var (
		av  []byte
		err error
	)
	if conn == nil {
		conn, err = dbus.SystemBus()
		if err != nil {
			return err
		}
	}

	av, err = hex.DecodeString(id[0:32])
	if err != nil {
		return err
	}
	obj := conn.Object("org.freedesktop.machine1", "/org/freedesktop/machine1")
	service := os.Getenv("container")
	if service == "" {
		service = "runc"
	}
	if len(name) > 32 {
		name = name[0:32]
	}

	return obj.Call("org.freedesktop.machine1.Manager.RegisterMachine", 0, name, av, service, "container", uint32(pid), root_directory).Err
}

// TerminateMachine registered with systemd on the host system
func TerminateMachine(name string) error {
	var err error
	if conn == nil {
		conn, err = dbus.SystemBus()
		if err != nil {
			return err
		}
	}
	obj := conn.Object("org.freedesktop.machine1", "/org/freedesktop/machine1")
	return obj.Call("org.freedesktop.machine1.Manager.TerminateMachine", 0, name).Err
}

const CONFIG = "/etc/oci-register-machine.conf"

var settings struct {
	Disabled bool `yaml:"disabled"`
}

func main() {
	var state State

	logwriter, err := syslog.New(syslog.LOG_NOTICE, "oci-register-machine")
	if err == nil {
		log.SetOutput(logwriter)
	}
	// then config file settings

	data, err := ioutil.ReadFile(CONFIG)
	if err != nil {
		if !os.IsNotExist(err) {
			log.Fatalf("RegisterMachine Failed to read %s %v", CONFIG, err.Error())
		}
	} else {
		if err := yaml.Unmarshal(data, &settings); err != nil {
			log.Fatalf("RegisterMachine Failed to parse %s %v", CONFIG, err.Error())
		}
		if settings.Disabled {
			return
		}
	}

	if err := json.NewDecoder(os.Stdin).Decode(&state); err != nil {
		log.Fatalf("RegisterMachine Failed %v", err.Error())
	}

	command := map[bool]string{true: "prestart", false: "poststop"}[state.Pid > 0]
	if len(os.Args) > 1 {
		command = os.Args[1]
	}

	log.Printf("Register machine: %s %s %d %s", command, state.ID, state.Pid, state.Root)
	passId := state.ID
	// If id is shorter than 32, then read container_uuid from the container process environment variables
	if len(passId) < 32 && state.Pid > 0 {
		var config Config
		configFile := fmt.Sprintf("%s/config.json", state.BundlePath)
		data, err := ioutil.ReadFile(configFile)
		if err != nil {
			log.Fatalf("RegisterMachine Failed to read %s %v", configFile, err.Error())
		}
		if err := yaml.Unmarshal(data, &config); err != nil {
			log.Fatalf("RegisterMachine Failed to parse %s %v", configFile, err.Error())
		}
		for _, env := range config.Process.Env {
			const PREFIX = "container_uuid="
			if strings.HasPrefix(env, PREFIX) {
				passId = strings.Replace(env[len(PREFIX):], "-", "", -1)
				break
			}
		}
	}
	// ensure id is a hex string at least 32 chars
	if len(passId) < 32 {
		passId, err = Validate(passId)
		if err != nil {
			log.Fatalf("RegisterMachine Failed %v", err.Error())
		}
	}

	switch command {
	case "prestart":
		{
			if err = RegisterMachine(state.ID, passId, int(state.Pid), state.Root); err != nil {
				log.Fatalf("Register machine failed: %v", err)
			}
			return
		}
	case "poststop":
		{
			if err := TerminateMachine(state.ID); err != nil {
				if !strings.Contains(err.Error(), "No machine") {
					log.Fatalf("TerminateMachine failed: %v", err)
				}
			}
			return
		}
		log.Fatalf("Invalid command %q must be prestart|poststop", command)
	}
}
<|endoftext|>


<commit_before>package ldap

import (
	"encoding/hex"
	"fmt"
	"regexp"
	"strings"

	l "github.com/go-ldap/ldap"
	"github.com/pkg/errors"
)

var (
	userRegexp = regexp.MustCompile(",[A-Z]+=")
)

func ParseUserCN(userDN string) (string, error) {
	dn, err := l.ParseDN(userDN)
	if err != nil {
		return "", errors.Wrapf(err, "Unable to parse userDN %s", userDN)
	}
	attributeName := dn.RDNs[0].Attributes[0].Type
	cn := dn.RDNs[0].Attributes[0].Value
	return fmt.Sprintf("%s=%s", attributeName, cn), nil
}

func EscapeFilterValue(filter string) string {
	return l.EscapeFilter(strings.Replace(filter, "\\", "", -1))
}

func UnescapeFilterValue(filter string) string {
	repl := unescapeFilterRegex.ReplaceAllFunc(
		[]byte(filter),
		func(match []byte) []byte {
			// \( \) \\ \*
			if len(match) == 2 {
				return []byte{match[1]}
			}
			// had issues with Decode, TODO fix to use Decode?.
			res, _ := hex.DecodeString(string(match[1:]))
			return res
		},
	)
	return string(repl)
}
<commit_msg>remove old regexpr that was no longer used<commit_after>package ldap

import (
	"encoding/hex"
	"fmt"
	"strings"

	l "github.com/go-ldap/ldap"
	"github.com/pkg/errors"
)

func ParseUserCN(userDN string) (string, error) {
	dn, err := l.ParseDN(userDN)
	if err != nil {
		return "", errors.Wrapf(err, "Unable to parse userDN %s", userDN)
	}
	attributeName := dn.RDNs[0].Attributes[0].Type
	cn := dn.RDNs[0].Attributes[0].Value
	return fmt.Sprintf("%s=%s", attributeName, cn), nil
}

func EscapeFilterValue(filter string) string {
	return l.EscapeFilter(strings.Replace(filter, "\\", "", -1))
}

func UnescapeFilterValue(filter string) string {
	repl := unescapeFilterRegex.ReplaceAllFunc(
		[]byte(filter),
		func(match []byte) []byte {
			// \( \) \\ \*
			if len(match) == 2 {
				return []byte{match[1]}
			}
			// had issues with Decode, TODO fix to use Decode?.
			res, _ := hex.DecodeString(string(match[1:]))
			return res
		},
	)
	return string(repl)
}
<|endoftext|>


<commit_before>package goapns

import (
	"bytes"
	"crypto/tls"
	"net/http"

	"encoding/json"
	"fmt"

	"golang.org/x/net/http2"
)

type Connection struct {
	HTTPClient  http.Client
	Certificate tls.Certificate
	Host        string
}

// Apple HTTP/2 Development & Production urls
const (
	HostDevelopment = "https://api.development.push.apple.com"
	HostProduction  = "https://api.push.apple.com"
)

func NewConnection(pathname string, key string) (*Connection, error) {
	c := &Connection{}

	cert, err := CertificateFromP12(pathname, key)
	if err != nil {
		//fmt.Printf("Error creating Connection: %v", err)
		return nil, err
	}
	c.Certificate = cert

	tlsConfig := &tls.Config{
		Certificates: []tls.Certificate{cert},
	}

	//no check if Certificate is present to fail hard if this requirement is not met
	tlsConfig.BuildNameToCertificate()

	transport := &http2.Transport{TLSClientConfig: tlsConfig}

	transport.AllowHTTP = true
	c.HTTPClient = http.Client{Transport: transport}
	//Default Host is Development Host.
	c.Host = HostDevelopment

	return c, nil
}

func (c *Connection) Development() *Connection {
	c.Host = HostDevelopment
	return c
}
func (c *Connection) Production() *Connection {
	c.Host = HostProduction
	return c
}

func (c *Connection) Push(message *Message, tokens []string, responseChannel chan Response) {
	// fmt.Printf("Will push to tokens %v , URL: %v\n", tokens, c.Host)
	dataToSend, err := json.Marshal(message)

	if err != nil {
		fmt.Printf("Error JSONING the request: %v\naborting\n", err)
		close(responseChannel)
		return
	}

	for index, token := range tokens {

		url := fmt.Sprintf("%v/3/device/%v", c.Host, token)
		request, err := http.NewRequest("POST", url, bytes.NewBuffer(dataToSend))
		if err != nil {
			fmt.Printf("Error creating request: %v\naborting\n", err)
			response := Response{}
			response.Error = err
			response.Message = message
			responseChannel <- response
			continue
		}

		configureHeader(request, message)
		push := func(token string, responseChannel chan Response, shouldCloseChannelWhenDone bool) {
			if shouldCloseChannelWhenDone {
				defer close(responseChannel)

				fmt.Printf("Closing channel\n")
			} else {
				fmt.Printf("was pushing to token %v with index %v\n", token, index)
			}

			httpResponse, err := c.HTTPClient.Do(request)
			if httpResponse != nil {
				defer httpResponse.Body.Close()
			}

			if err != nil {
				fmt.Printf("Error during response: %v\nAborting.\n", err)

				response := Response{}
				response.Error = err
				response.Message = message
				response.Token = token
				responseChannel <- response
			} else {

				//Response object that will be populated and passed into the responseChannel
				var response Response

				if httpResponse.StatusCode != http.StatusOK {
					//Something went wrong, creating new Response object from the JSON response
					errParsingJSON := json.NewDecoder(httpResponse.Body).Decode(&response)

					if errParsingJSON != nil {
						//We could not parse the response into JSON, we need to pass the received error into the responseChannel
						response.Error = err

					} else {
						//We have parsed the error and populated a new Response object with it.

						//Converting the JSON body (string) into an error object
						knownError, found := errorReason[response.Reason]

						if !found {
							//We could not find the error in our map so we try to use the HTTP status code to produce some meaningful error object
							knownError, found = errorStatus[httpResponse.StatusCode]

							if !found {
								//Could not find the error anywhere :(
								knownError = ErrorUnknown
							}
						}
						response.Error = knownError
					}
				}

				response.Message = message
				response.Token = token
				response.StatusCode = httpResponse.StatusCode
				responseChannel <- response
			}
		}
		shouldCloseChannelWhenDone := index == (len(tokens) - 1)
		go push(token, responseChannel, shouldCloseChannelWhenDone)

	}

}

func configureHeader(request *http.Request, message *Message) {
	request.Header.Set("Content-Type", "application/json; charset=utf-8")

	if message.Header.APNSID != "" {
		request.Header.Set("apns-id", message.Header.APNSID)
	}

	if !message.Header.Expiration.IsZero() {
		request.Header.Set("apns-expiration", fmt.Sprintf("%v", message.Header.Expiration.Unix()))
	}
	//Only set the priority if it is low because high is the default
	//value that is assumed when no priority is specified.
	//We want to omit everything we can to save bandwith.
	if message.Header.Priority == PriorityLow {
		request.Header.Set("apns-priority", fmt.Sprintf("%v", message.Header.Priority))
	}
	if message.Header.Topic != "" {
		request.Header.Set("apns-topic", message.Header.Topic)
	}
}
<commit_msg>More documentation in Connection.go<commit_after>package goapns

import (
	"bytes"
	"crypto/tls"
	"net/http"

	"encoding/json"
	"fmt"

	"golang.org/x/net/http2"
)

//Connection stores properties that are necessary to perform a request to Apples servers.
type Connection struct {
	//HTTPClient the HTTP client that is used. It is configured with a tls.Config that uses
	//the specified certificate. It is constructed for you in NewConnection(pathname, key)
	HTTPClient http.Client
	//Certificate is the certificate that you specified during construction of the Connection
	//by using NewConnection(pathname string, key string)
	Certificate tls.Certificate
	//Host is the host to which the request is sent to.
	Host string
}

// Apple HTTP/2 Development & Production urls
const (
	HostDevelopment = "https://api.development.push.apple.com"
	HostProduction  = "https://api.push.apple.com"
)

//NewConnection creates a new Connection object. A Certificate is required to
//send requests to Apples servers. You can specify the path to a .p12 certificate
//and its passphrase.
//The default host is the development host. connection.Production() if you want to
//use the production environment.
//It will return a *Connection or an error. One of this is always nil.
func NewConnection(pathname string, key string) (*Connection, error) {
	c := &Connection{}

	cert, err := CertificateFromP12(pathname, key)
	if err != nil {
		//fmt.Printf("Error creating Connection: %v", err)
		return nil, err
	}
	c.Certificate = cert

	tlsConfig := &tls.Config{
		Certificates: []tls.Certificate{cert},
	}

	//no check if Certificate is present to fail hard if this requirement is not met
	tlsConfig.BuildNameToCertificate()

	transport := &http2.Transport{TLSClientConfig: tlsConfig}

	c.HTTPClient = http.Client{Transport: transport}
	//Default Host is Development Host.
	c.Host = HostDevelopment

	return c, nil
}

//Development sets the host to Apples development environment.
//Use this while your app is in development and not published.
//This host is set by default.
func (c *Connection) Development() *Connection {
	c.Host = HostDevelopment
	return c
}

//Production sets the host to Apples development environment.
//Use this while your app is in production.
func (c *Connection) Production() *Connection {
	c.Host = HostProduction
	return c
}

func (c *Connection) Push(message *Message, tokens []string, responseChannel chan Response) {
	// fmt.Printf("Will push to tokens %v , URL: %v\n", tokens, c.Host)
	dataToSend, err := json.Marshal(message)

	if err != nil {
		fmt.Printf("Error JSONING the request: %v\naborting\n", err)
		close(responseChannel)
		return
	}

	for index, token := range tokens {

		url := fmt.Sprintf("%v/3/device/%v", c.Host, token)
		request, err := http.NewRequest("POST", url, bytes.NewBuffer(dataToSend))
		if err != nil {
			fmt.Printf("Error creating request: %v\naborting\n", err)
			response := Response{}
			response.Error = err
			response.Message = message
			responseChannel <- response
			continue
		}

		configureHeader(request, message)
		push := func(token string, responseChannel chan Response, shouldCloseChannelWhenDone bool) {
			if shouldCloseChannelWhenDone {
				defer close(responseChannel)

				fmt.Printf("Closing channel\n")
			} else {
				fmt.Printf("was pushing to token %v with index %v\n", token, index)
			}

			httpResponse, err := c.HTTPClient.Do(request)
			if httpResponse != nil {
				defer httpResponse.Body.Close()
			}

			if err != nil {
				fmt.Printf("Error during response: %v\nAborting.\n", err)

				response := Response{}
				response.Error = err
				response.Message = message
				response.Token = token
				responseChannel <- response
			} else {

				//Response object that will be populated and passed into the responseChannel
				var response Response

				if httpResponse.StatusCode != http.StatusOK {
					//Something went wrong, creating new Response object from the JSON response
					errParsingJSON := json.NewDecoder(httpResponse.Body).Decode(&response)

					if errParsingJSON != nil {
						//We could not parse the response into JSON, we need to pass the received error into the responseChannel
						response.Error = err

					} else {
						//We have parsed the error and populated a new Response object with it.

						//Converting the JSON body (string) into an error object
						knownError, found := errorReason[response.Reason]

						if !found {
							//We could not find the error in our map so we try to use the HTTP status code to produce some meaningful error object
							knownError, found = errorStatus[httpResponse.StatusCode]

							if !found {
								//Could not find the error anywhere :(
								knownError = ErrorUnknown
							}
						}
						response.Error = knownError
					}
				}

				response.Message = message
				response.Token = token
				response.StatusCode = httpResponse.StatusCode
				responseChannel <- response
			}
		}
		shouldCloseChannelWhenDone := index == (len(tokens) - 1)
		go push(token, responseChannel, shouldCloseChannelWhenDone)

	}

}

func configureHeader(request *http.Request, message *Message) {
	request.Header.Set("Content-Type", "application/json; charset=utf-8")

	if message.Header.APNSID != "" {
		request.Header.Set("apns-id", message.Header.APNSID)
	}

	if !message.Header.Expiration.IsZero() {
		request.Header.Set("apns-expiration", fmt.Sprintf("%v", message.Header.Expiration.Unix()))
	}
	//Only set the priority if it is low because high is the default
	//value that is assumed when no priority is specified.
	//We want to omit everything we can to save bandwith.
	if message.Header.Priority == PriorityLow {
		request.Header.Set("apns-priority", fmt.Sprintf("%v", message.Header.Priority))
	}
	if message.Header.Topic != "" {
		request.Header.Set("apns-topic", message.Header.Topic)
	}
}
<|endoftext|>


<commit_before>package lib

import (
	"fmt"
	"log"
	"net"
	"strings"

	"github.com/bruceadowns/syslogparser"
	"github.com/bruceadowns/syslogparser/mako"
	"github.com/bruceadowns/syslogparser/rfc3164"
	"github.com/bruceadowns/syslogparser/rfc3164raw"
	"github.com/bruceadowns/syslogparser/rfc5424"
	"github.com/bruceadowns/syslogparser/rfc5424raw"
	"github.com/bruceadowns/syslogparser/syslogmako"
)

// Packet holds the incoming traffic info
type Packet struct {
	Address  net.Addr
	Message  []byte
	LogEvent *LogEvent
}

var remoteTypeCache = make(map[string]string)

func (p *Packet) String() string {
	return fmt.Sprintf("Address: %s '%s'", p.Address, p.Message)
}

// IsValid returns T/F
func (p *Packet) IsValid() bool {
	if len(p.Address.String()) == 0 {
		log.Print("Address is empty")
		return false
	}

	if len(p.Message) == 0 {
		log.Print("Message is empty")
		return false
	}

	return true
}

type nullParser struct {
	host string
	buff []byte
}

// Parse ...
func (p *nullParser) Parse() error {
	return nil
}

// Dump ...
func (p *nullParser) Dump() syslogparser.LogParts {
	return syslogparser.LogParts{
		"hostname": p.host,
		"message":  string(p.buff),
	}
}

func populate(p syslogparser.LogParser) (res *LogEvent) {
	if p == nil {
		return
	}

	logParts := p.Dump()

	app := logParts["app_name"]
	if len(app) == 0 {
		app = logParts["service_name"]
	}

	pid := logParts["service_version"]
	if len(pid) == 0 {
		pid = logParts["proc_id"]
		if len(pid) == 0 {
			pid = logParts["tag"]
		}
	}

	version := logParts["@version"]
	if len(version) == 0 {
		version = logParts["version"]
	}

	message := logParts["message"]
	if len(message) == 0 {
		message = logParts["content"]
	}

	timestamp := logParts["@timestamp"]
	if len(timestamp) == 0 {
		timestamp = logParts["timestamp"]
	}

	stackTrace := []string{}
	fullStackTrace := logParts["stack_trace"]
	if len(fullStackTrace) > 0 {
		stackTrace = strings.Split(fullStackTrace, "\n")
	}

	res = &LogEvent{
		DataCenter:       logParts["service_environment"],
		Cluster:          logParts["service_pipeline"],
		Host:             logParts["hostname"],
		Service:          app,
		Instance:         pid,
		Version:          version,
		Level:            logParts["level"],
		ThreadName:       logParts["thread_name"],
		LoggerName:       logParts["logger_name"],
		Message:          message,
		Timestamp:        timestamp,
		ThrownStackTrace: stackTrace,
	}

	return
}

// Mill determines message type and parses into a LogEvent
func (p *Packet) Mill() (res *LogEvent) {
	log.Printf("%s", p)

	var parser syslogparser.LogParser

	for {
		// check cache for known type

		{
			parser = mako.NewParser(p.Message, p.Address.String())
			if err := parser.Parse(); err == nil {
				remoteTypeCache[p.Address.String()] = "mako"
				log.Printf("mako")
				break
			}
		}

		{
			parser = syslogmako.NewParser(p.Message)
			if err := parser.Parse(); err == nil {
				remoteTypeCache[p.Address.String()] = "syslogmako"
				log.Printf("syslogmako")
				break
			}
		}

		{
			parser = rfc5424raw.NewParser(p.Message)
			if err := parser.Parse(); err == nil {
				remoteTypeCache[p.Address.String()] = "rfc5424raw"
				log.Printf("rfc5424raw")
				break
			}
		}

		{
			parser = rfc3164raw.NewParser(p.Message)
			if err := parser.Parse(); err == nil {
				remoteTypeCache[p.Address.String()] = "rfc3164raw"
				log.Printf("rfc3164raw")
				break
			}
		}

		{
			parser = rfc3164.NewParser(p.Message)
			if err := parser.Parse(); err == nil {
				remoteTypeCache[p.Address.String()] = "rfc3164"
				log.Printf("rfc3164")
				break
			}
		}

		{
			parser = rfc5424.NewParser(p.Message)
			if err := parser.Parse(); err == nil {
				remoteTypeCache[p.Address.String()] = "rfc5424"
				log.Printf("rfc5424")
				break
			}
		}

		{
			parser = &nullParser{buff: p.Message, host: p.Address.String()}
			log.Printf("empty")
			break
		}
	}

	res = populate(parser)
	if res == nil {
		log.Printf("Message from %s not parsed: %s", p.Address, p.Message)
	} else {
		log.Print(res)
	}

	return
}
<commit_msg>Changed name for no-op catch-all parser<commit_after>package lib

import (
	"fmt"
	"log"
	"net"
	"strings"

	"github.com/bruceadowns/syslogparser"
	"github.com/bruceadowns/syslogparser/mako"
	"github.com/bruceadowns/syslogparser/rfc3164"
	"github.com/bruceadowns/syslogparser/rfc3164raw"
	"github.com/bruceadowns/syslogparser/rfc5424"
	"github.com/bruceadowns/syslogparser/rfc5424raw"
	"github.com/bruceadowns/syslogparser/syslogmako"
)

// Packet holds the incoming traffic info
type Packet struct {
	Address  net.Addr
	Message  []byte
	LogEvent *LogEvent
}

var remoteTypeCache = make(map[string]string)

func (p *Packet) String() string {
	return fmt.Sprintf("Address: %s '%s'", p.Address, p.Message)
}

// IsValid returns T/F
func (p *Packet) IsValid() bool {
	if len(p.Address.String()) == 0 {
		log.Print("Address is empty")
		return false
	}

	if len(p.Message) == 0 {
		log.Print("Message is empty")
		return false
	}

	return true
}

type noopParser struct {
	host string
	buff []byte
}

// Parse ...
func (p *noopParser) Parse() error {
	return nil
}

// Dump ...
func (p *noopParser) Dump() syslogparser.LogParts {
	return syslogparser.LogParts{
		"hostname": p.host,
		"message":  string(p.buff),
	}
}

func populate(p syslogparser.LogParser) (res *LogEvent) {
	if p == nil {
		return
	}

	logParts := p.Dump()

	app := logParts["app_name"]
	if len(app) == 0 {
		app = logParts["service_name"]
	}

	pid := logParts["service_version"]
	if len(pid) == 0 {
		pid = logParts["proc_id"]
		if len(pid) == 0 {
			pid = logParts["tag"]
		}
	}

	version := logParts["@version"]
	if len(version) == 0 {
		version = logParts["version"]
	}

	message := logParts["message"]
	if len(message) == 0 {
		message = logParts["content"]
	}

	timestamp := logParts["@timestamp"]
	if len(timestamp) == 0 {
		timestamp = logParts["timestamp"]
	}

	stackTrace := []string{}
	fullStackTrace := logParts["stack_trace"]
	if len(fullStackTrace) > 0 {
		stackTrace = strings.Split(fullStackTrace, "\n")
	}

	res = &LogEvent{
		DataCenter:       logParts["service_environment"],
		Cluster:          logParts["service_pipeline"],
		Host:             logParts["hostname"],
		Service:          app,
		Instance:         pid,
		Version:          version,
		Level:            logParts["level"],
		ThreadName:       logParts["thread_name"],
		LoggerName:       logParts["logger_name"],
		Message:          message,
		Timestamp:        timestamp,
		ThrownStackTrace: stackTrace,
	}

	return
}

// Mill determines message type and parses into a LogEvent
func (p *Packet) Mill() (res *LogEvent) {
	log.Printf("%s", p)

	var parser syslogparser.LogParser

	for {
		// check cache for known type

		{
			parser = mako.NewParser(p.Message, p.Address.String())
			if err := parser.Parse(); err == nil {
				remoteTypeCache[p.Address.String()] = "mako"
				log.Printf("mako")
				break
			}
		}

		{
			parser = syslogmako.NewParser(p.Message)
			if err := parser.Parse(); err == nil {
				remoteTypeCache[p.Address.String()] = "syslogmako"
				log.Printf("syslogmako")
				break
			}
		}

		{
			parser = rfc5424raw.NewParser(p.Message)
			if err := parser.Parse(); err == nil {
				remoteTypeCache[p.Address.String()] = "rfc5424raw"
				log.Printf("rfc5424raw")
				break
			}
		}

		{
			parser = rfc3164raw.NewParser(p.Message)
			if err := parser.Parse(); err == nil {
				remoteTypeCache[p.Address.String()] = "rfc3164raw"
				log.Printf("rfc3164raw")
				break
			}
		}

		{
			parser = rfc3164.NewParser(p.Message)
			if err := parser.Parse(); err == nil {
				remoteTypeCache[p.Address.String()] = "rfc3164"
				log.Printf("rfc3164")
				break
			}
		}

		{
			parser = rfc5424.NewParser(p.Message)
			if err := parser.Parse(); err == nil {
				remoteTypeCache[p.Address.String()] = "rfc5424"
				log.Printf("rfc5424")
				break
			}
		}

		{
			parser = &noopParser{buff: p.Message, host: p.Address.String()}
			log.Printf("empty")
			break
		}
	}

	res = populate(parser)
	if res == nil {
		log.Printf("Message from %s not parsed: %s", p.Address, p.Message)
	} else {
		log.Print(res)
	}

	return
}
<|endoftext|>


<commit_before>/*
Copyright IBM Corp. 2016 All Rights Reserved.

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 obcpbft

import (
	"testing"
	"time"

	"github.com/hyperledger/fabric/consensus"

	"github.com/spf13/viper"
)

func (op *obcBatch) getPBFTCore() *pbftCore {
	return op.pbft
}

func obcBatchHelper(id uint64, config *viper.Viper, stack consensus.Stack) pbftConsumer {
	// It's not entirely obvious why the compiler likes the parent function, but not newObcBatch directly
	return newObcBatch(id, config, stack)
}

func TestNetworkBatch(t *testing.T) {
	batchSize := 2
	validatorCount := 4
	net := makeConsumerNetwork(validatorCount, obcBatchHelper, func(ce *consumerEndpoint) {
		ce.consumer.(*obcBatch).batchSize = batchSize
	})
	defer net.stop()

	broadcaster := net.endpoints[generateBroadcaster(validatorCount)].getHandle()
	err := net.endpoints[1].(*consumerEndpoint).consumer.RecvMsg(createOcMsgWithChainTx(1), broadcaster)
	if err != nil {
		t.Fatalf("External request was not processed by backup: %v", err)
	}

	net.process()

	if l := len(net.endpoints[0].(*consumerEndpoint).consumer.(*obcBatch).batchStore); l != 1 {
		t.Fatalf("%d message expected in primary's batchStore, found %d", 1, l)
	}

	err = net.endpoints[2].(*consumerEndpoint).consumer.RecvMsg(createOcMsgWithChainTx(2), broadcaster)
	net.process()

	if l := len(net.endpoints[0].(*consumerEndpoint).consumer.(*obcBatch).batchStore); l != 0 {
		t.Fatalf("%d messages expected in primary's batchStore, found %d", 0, l)
	}

	for _, ep := range net.endpoints {
		ce := ep.(*consumerEndpoint)
		block, err := ce.consumer.(*obcBatch).stack.GetBlock(1)
		if nil != err {
			t.Fatalf("Replica %d executed requests, expected a new block on the chain, but could not retrieve it : %s", ce.id, err)
		}
		numTrans := len(block.Transactions)
		if numTrans != batchSize {
			t.Fatalf("Replica %d executed %d requests, expected %d",
				ce.id, numTrans, batchSize)
		}
		if numTxResults := len(block.NonHashData.TransactionResults); numTxResults != 1 /*numTrans*/ {
			t.Fatalf("Replica %d has %d txResults, expected %d", ce.id, numTxResults, numTrans)
		}
	}
}

func TestBatchCustody(t *testing.T) {
	validatorCount := 4
	net := makeConsumerNetwork(validatorCount, func(id uint64, config *viper.Viper, stack consensus.Stack) pbftConsumer {
		config.Set("general.batchsize", "2")
		config.Set("general.timeout.batch", "500ms")
		config.Set("general.timeout.request", "800ms")
		config.Set("general.timeout.viewchange", "1600ms")
		return newObcBatch(id, config, stack)
	})
	net.filterFn = func(src int, dst int, payload []byte) []byte {
		logger.Info("msg from %d to %d", src, dst)
		if src == 0 {
			return nil
		}
		return payload
	}

	go net.processContinually()
	r2 := net.endpoints[2].(*consumerEndpoint).consumer
	r2.RecvMsg(createOcMsgWithChainTx(1), net.endpoints[1].getHandle())
	r2.RecvMsg(createOcMsgWithChainTx(2), net.endpoints[1].getHandle())
	time.Sleep(6 * time.Second)
	net.stop()

	for _, inst := range net.endpoints {
		inst := inst.(*consumerEndpoint)
		_, err := inst.consumer.(*obcBatch).stack.GetBlock(1)
		if err != nil {
			t.Errorf("Expected replica %d to have one block", inst.id)
			continue
		}
	}
}
<commit_msg>pbft/batch: ignore byzantine node state in test<commit_after>/*
Copyright IBM Corp. 2016 All Rights Reserved.

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 obcpbft

import (
	"testing"
	"time"

	"github.com/hyperledger/fabric/consensus"

	"github.com/spf13/viper"
)

func (op *obcBatch) getPBFTCore() *pbftCore {
	return op.pbft
}

func obcBatchHelper(id uint64, config *viper.Viper, stack consensus.Stack) pbftConsumer {
	// It's not entirely obvious why the compiler likes the parent function, but not newObcBatch directly
	return newObcBatch(id, config, stack)
}

func TestNetworkBatch(t *testing.T) {
	batchSize := 2
	validatorCount := 4
	net := makeConsumerNetwork(validatorCount, obcBatchHelper, func(ce *consumerEndpoint) {
		ce.consumer.(*obcBatch).batchSize = batchSize
	})
	defer net.stop()

	broadcaster := net.endpoints[generateBroadcaster(validatorCount)].getHandle()
	err := net.endpoints[1].(*consumerEndpoint).consumer.RecvMsg(createOcMsgWithChainTx(1), broadcaster)
	if err != nil {
		t.Fatalf("External request was not processed by backup: %v", err)
	}

	net.process()

	if l := len(net.endpoints[0].(*consumerEndpoint).consumer.(*obcBatch).batchStore); l != 1 {
		t.Fatalf("%d message expected in primary's batchStore, found %d", 1, l)
	}

	err = net.endpoints[2].(*consumerEndpoint).consumer.RecvMsg(createOcMsgWithChainTx(2), broadcaster)
	net.process()

	if l := len(net.endpoints[0].(*consumerEndpoint).consumer.(*obcBatch).batchStore); l != 0 {
		t.Fatalf("%d messages expected in primary's batchStore, found %d", 0, l)
	}

	for _, ep := range net.endpoints {
		ce := ep.(*consumerEndpoint)
		block, err := ce.consumer.(*obcBatch).stack.GetBlock(1)
		if nil != err {
			t.Fatalf("Replica %d executed requests, expected a new block on the chain, but could not retrieve it : %s", ce.id, err)
		}
		numTrans := len(block.Transactions)
		if numTrans != batchSize {
			t.Fatalf("Replica %d executed %d requests, expected %d",
				ce.id, numTrans, batchSize)
		}
		if numTxResults := len(block.NonHashData.TransactionResults); numTxResults != 1 /*numTrans*/ {
			t.Fatalf("Replica %d has %d txResults, expected %d", ce.id, numTxResults, numTrans)
		}
	}
}

func TestBatchCustody(t *testing.T) {
	validatorCount := 4
	net := makeConsumerNetwork(validatorCount, func(id uint64, config *viper.Viper, stack consensus.Stack) pbftConsumer {
		config.Set("general.batchsize", "2")
		config.Set("general.timeout.batch", "500ms")
		config.Set("general.timeout.request", "800ms")
		config.Set("general.timeout.viewchange", "1600ms")
		return newObcBatch(id, config, stack)
	})
	net.filterFn = func(src int, dst int, payload []byte) []byte {
		logger.Info("msg from %d to %d", src, dst)
		if src == 0 {
			return nil
		}
		return payload
	}

	go net.processContinually()
	r2 := net.endpoints[2].(*consumerEndpoint).consumer
	r2.RecvMsg(createOcMsgWithChainTx(1), net.endpoints[1].getHandle())
	r2.RecvMsg(createOcMsgWithChainTx(2), net.endpoints[1].getHandle())
	time.Sleep(6 * time.Second)
	net.stop()

	for i, inst := range net.endpoints {
		// Don't care about byzantine node 0
		if i == 0 {
			continue
		}
		inst := inst.(*consumerEndpoint)
		_, err := inst.consumer.(*obcBatch).stack.GetBlock(1)
		if err != nil {
			t.Errorf("Expected replica %d to have one block", inst.id)
			continue
		}
	}
}
<|endoftext|>


<commit_before>// properties: This package implements access to .properties file
// See further details on http://en.wikipedia.org/wiki/.properties
package properties

import "io"
import "os"
import "utf8"

// Error represents an unexpected I/O behavior.
type Error struct {
	os.ErrorString;
}

// ErrMalformedUtf8Encoding means that it was not possible to convert \uXXXX
// string to utf8 rune.
var ErrMalformedUtf8Encoding os.Error = &Error{"malformed \\uxxxx encoding"}

// Reads key value pairs from reader and returns map[string]string
func Load(src io.Reader) (props map[string]string, err os.Error) {
	err = nil;
	lr := newLineReader(src);
	props = make(map[string]string);
	for {
		s, e := lr.readLine();
		if e == os.EOF {
			break;
		}
		if e != nil {
			return nil, e;
		}

		keyLen := 0;
		precedingBackslash := false;
		hasSep := false;
		valueStart := len(s);

		for keyLen < len(s) {
			c := s[keyLen];

			if (c == '=' || c == ':') && !precedingBackslash {
				valueStart = keyLen + 1;
				hasSep = true;
				break;
			} else if (c == ' ' || c == '\t' || c == '\f') && !precedingBackslash {
				valueStart = keyLen + 1;
				break;
			}
			if c == '\\' {
				precedingBackslash = !precedingBackslash
			} else {
				precedingBackslash = false
			}

			keyLen++;
		}

		for valueStart < len(s) {
			c := s[valueStart];
			if c != ' ' && c != '\t' && c != '\f' {
				if !hasSep && (c == '=' || c == ':') {
					hasSep = true
				} else {
					break
				}
			}
			valueStart++;
		}
		key, err := decodeString(s[0:keyLen]);
		if err != nil {
			return nil, err
		}
		value, err := decodeString(s[valueStart:len(s)]);
		if err != nil {
			return nil, err
		}
		props[key] = value;
	}
	return props, err;
}

func decodeString(in string) (string, os.Error) {
	out := make([]byte, len(in));
	o := -1;
	for i := 0; i < len(in); {
		o++;
		if in[i] == '\\' {
			i++;
			switch in[i] {
			case 'u':
				i++;
				rune := 0;
				for j := 0; j < 4; j++ {
					switch {
					case in[i] >= '0' && in[i] <= '9':
						rune = (rune << 4) + int(in[i]) - '0';
						break;
					case in[i] >= 'a' && in[i] <= 'f':
						rune = (rune << 4) + 10 + int(in[i]) - 'a';
						break;
					case in[i] >= 'A' && in[i] <= 'F':
						rune = (rune << 4) + 10 + int(in[i]) - 'A';
						break;
					default:
						return "", ErrMalformedUtf8Encoding
					}
					i++;
				}
				bytes := make([]byte, utf8.RuneLen(rune));
				bytesWritten := utf8.EncodeRune(rune, bytes);
				for j := 0; j < bytesWritten; j++ {
					out[o] = bytes[j];
					o++;
				}
				continue;
			case 't':
				out[o] = '\t';
				i++;
				continue;
			case 'r':
				out[o] = '\r';
				i++;
				continue;
			case 'n':
				out[o] = '\n';
				i++;
				continue;
			case 'f':
				out[o] = '\f';
				i++;
				continue;
			}
			out[o] = in[i];
			i++;
			continue;
		}
		out[o] = in[i];
		i++;
	}

	return string(out), nil;
}

/* Read in a "logical line" from an InputStream/Reader, skip all comment
 * and blank lines and filter out those leading whitespace characters
 * (\u0020, \u0009 and \u000c) from the beginning of a "natural line".
 * Method returns the char length of the "logical line" and stores
 * the line in "buffer".
 */
type lineReader struct {
	reader		io.Reader;
	buffer		[]byte;
	lineBuffer	[]byte;
	limit		int;
	offset		int;
	exhausted	bool;
}

func newLineReader(r io.Reader) *lineReader {
	n := new(lineReader);
	n.reader = r;
	n.buffer = make([]byte, 1024);
	n.lineBuffer = make([]byte, 1024);
	n.limit = 0;
	n.offset = 0;
	n.exhausted = false;
	return n;
}

func (lr *lineReader) readLine() (line string, e os.Error) {
	if lr.exhausted {
		return "", os.EOF
	}
	nextCharIndex := 0;
	char := byte(0);

	skipLF := false;
	skipWhiteSpace := true;
	appendedLineBegin := false;
	isNewLine := true;
	isCommentLine := false;
	precedingBackslash := false;

	for {
		if lr.offset >= lr.limit {
			lr.limit, e = io.ReadFull(lr.reader, lr.buffer);
			lr.offset = 0;
			if e == os.EOF {
				lr.exhausted = true;
				if isCommentLine {
					return "", os.EOF
				}
				return string(lr.lineBuffer[0:nextCharIndex]), nil;
			}
			if e == io.ErrUnexpectedEOF {
				if isCommentLine {
					return "", os.EOF
				}
				continue;
			}
			if e != nil {
				lr.exhausted = true;
				return "", e;
			}
		}

		char = lr.buffer[lr.offset];
		lr.offset++;

		if skipLF {
			skipLF = false;
			if char == '\n' {
				continue
			}
		}

		if skipWhiteSpace {
			if char == ' ' || char == '\t' || char == '\f' {
				continue
			}
			if !appendedLineBegin && (char == '\r' || char == '\n') {
				continue
			}
			skipWhiteSpace = false;
			appendedLineBegin = false;
		}

		if isNewLine {
			isNewLine = false;
			if char == '#' || char == '!' {
				isCommentLine = true;
				continue;
			}
		}

		if char != '\n' && char != '\r' {
			lr.lineBuffer[nextCharIndex] = char;
			nextCharIndex++;
			if nextCharIndex == len(lr.lineBuffer) {
				newBuffer := make([]byte, len(lr.lineBuffer)*2);
				for i, x := range lr.lineBuffer {
					newBuffer[i] = x
				}
				lr.lineBuffer = newBuffer;
			}
			//flip the preceding backslash flag
			precedingBackslash = char == '\\' && !precedingBackslash;
		} else {
			// reached EOL
			if isCommentLine || nextCharIndex == 0 {
				isCommentLine = false;
				isNewLine = true;
				skipWhiteSpace = true;
				nextCharIndex = 0;
				continue;
			}
			if lr.offset >= lr.limit {
				lr.limit, e = io.ReadFull(lr.reader, lr.buffer);
				lr.offset = 0;
				if e == os.EOF || e == io.ErrUnexpectedEOF {
					lr.exhausted = true;
					return string(lr.lineBuffer[0:nextCharIndex]), nil;
				}
				if e != nil {
					lr.exhausted = true;
					return "", e;
				}
			}
			if precedingBackslash {
				nextCharIndex--;
				//skip the leading whitespace characters in following line
				skipWhiteSpace = true;
				appendedLineBegin = true;
				precedingBackslash = false;
				if char == '\r' {
					skipLF = true
				}
			} else {
				return string(lr.lineBuffer[0:nextCharIndex]), nil
			}
		}
	}

	return "", nil;
}
<commit_msg>added package description<commit_after>// properties: This package implements access to .properties file
//
// .properties is a file extension for files mainly used in Java related
// technologies to store the configurable parameters of an application.
// They can also be used for storing strings for Internationalization and
// localization; these are known as Property Resource Bundles.
//
// Each parameter is stored as a pair of strings, one storing the name of
// the parameter (called the key), and the other storing the value.
//
// Each line in a .properties file normally stores a single property.
// Several formats are possible for each line, including key=value,
// key = value, key:value, and key value.
//
// .properties files can use the number sign (#) or the exclamation mark (!)
// as the first non blank character in a line to denote that all text following
// it is a comment. The backwards slash is used to escape a character.
// An example of a properties file is provided below.
// <code>
// # You are reading the ".properties" entry.
// ! The exclamation mark can also mark text as comments.
// website = http://en.wikipedia.org/
// language = English
// # The backslash below tells the application to continue reading
// # the value onto the next line.
// message = Welcome to \
//           Wikipedia!
// # Add spaces to the key
// key\ with\ spaces = This is the value that could be looked up with the \
// key "key with spaces".
// # Empty lines are skipped
//
// # Unicode
// unicode=\u041f\u0440\u0438\u0432\u0435\u0442, \u0421\u043e\u0432\u0430!
// # Comment
// </code>
//
// In the example above, website would be a key, and its corresponding
// value would be http://en.wikipedia.org/. While the number sign and the
// exclamation mark marks text as comments, it has no effect when it is part
// of a property. Thus, the key message has the value Welcome to Wikipedia!
// and not Welcome to Wikipedia. Note also that all of the whitespace in
// front of Wikipedia! is excluded completely.
//
// The encoding of a .properties file is ISO-8859-1, also known as Latin-1. All non-Latin-1 characters must be entered by using Unicode escape characters, e. g. \uHHHH where HHHH is a hexadecimal index of the character in the Unicode character set. This allows for using .properties files as resource bundles for localization. A non-Latin-1 text file can be converted to a correct .properties file by using the native2ascii tool that is shipped with the JDK or by using a tool, such as po2prop[1], that manages the transformation from a bilingual localization format into .properties escaping.
//
// From Wikipedia, the free encyclopedia
// http://en.wikipedia.org/wiki/.properties
package properties

import "io"
import "os"
import "utf8"

// Error represents an unexpected behavior.
type Error struct {
	os.ErrorString;
}

// ErrMalformedUtf8Encoding means that it was not possible to convert \uXXXX
// string to utf8 rune.
var ErrMalformedUtf8Encoding os.Error = &Error{"malformed \\uxxxx encoding"}

// Reads key value pairs from reader and returns map[string]string
func Load(src io.Reader) (props map[string]string, err os.Error) {
	err = nil;
	lr := newLineReader(src);
	props = make(map[string]string);
	for {
		s, e := lr.readLine();
		if e == os.EOF {
			break;
		}
		if e != nil {
			return nil, e;
		}

		keyLen := 0;
		precedingBackslash := false;
		hasSep := false;
		valueStart := len(s);

		for keyLen < len(s) {
			c := s[keyLen];

			if (c == '=' || c == ':') && !precedingBackslash {
				valueStart = keyLen + 1;
				hasSep = true;
				break;
			} else if (c == ' ' || c == '\t' || c == '\f') && !precedingBackslash {
				valueStart = keyLen + 1;
				break;
			}
			if c == '\\' {
				precedingBackslash = !precedingBackslash
			} else {
				precedingBackslash = false
			}

			keyLen++;
		}

		for valueStart < len(s) {
			c := s[valueStart];
			if c != ' ' && c != '\t' && c != '\f' {
				if !hasSep && (c == '=' || c == ':') {
					hasSep = true
				} else {
					break
				}
			}
			valueStart++;
		}
		key, err := decodeString(s[0:keyLen]);
		if err != nil {
			return nil, err
		}
		value, err := decodeString(s[valueStart:len(s)]);
		if err != nil {
			return nil, err
		}
		props[key] = value;
	}
	return props, err;
}

// Decodes \t,\n,\r,\f and \uXXXX characters in string
func decodeString(in string) (string, os.Error) {
	out := make([]byte, len(in));
	o := -1;
	for i := 0; i < len(in); {
		o++;
		if in[i] == '\\' {
			i++;
			switch in[i] {
			case 'u':
				i++;
				rune := 0;
				for j := 0; j < 4; j++ {
					switch {
					case in[i] >= '0' && in[i] <= '9':
						rune = (rune << 4) + int(in[i]) - '0';
						break;
					case in[i] >= 'a' && in[i] <= 'f':
						rune = (rune << 4) + 10 + int(in[i]) - 'a';
						break;
					case in[i] >= 'A' && in[i] <= 'F':
						rune = (rune << 4) + 10 + int(in[i]) - 'A';
						break;
					default:
						return "", ErrMalformedUtf8Encoding
					}
					i++;
				}
				bytes := make([]byte, utf8.RuneLen(rune));
				bytesWritten := utf8.EncodeRune(rune, bytes);
				for j := 0; j < bytesWritten; j++ {
					out[o] = bytes[j];
					o++;
				}
				continue;
			case 't':
				out[o] = '\t';
				i++;
				continue;
			case 'r':
				out[o] = '\r';
				i++;
				continue;
			case 'n':
				out[o] = '\n';
				i++;
				continue;
			case 'f':
				out[o] = '\f';
				i++;
				continue;
			}
			out[o] = in[i];
			i++;
			continue;
		}
		out[o] = in[i];
		i++;
	}

	return string(out), nil;
}

// Read in a "logical line" from an InputStream/Reader, skip all comment
// and blank lines and filter out those leading whitespace characters
// (\u0020, \u0009 and \u000c) from the beginning of a "natural line".
type lineReader struct {
	reader		io.Reader;
	buffer		[]byte;
	lineBuffer	[]byte;
	limit		int;
	offset		int;
	exhausted	bool;
}

func newLineReader(r io.Reader) *lineReader {
	n := new(lineReader);
	n.reader = r;
	n.buffer = make([]byte, 1024);
	n.lineBuffer = make([]byte, 1024);
	n.limit = 0;
	n.offset = 0;
	n.exhausted = false;
	return n;
}

// Returns the "logical line" from given reader
func (lr *lineReader) readLine() (line string, e os.Error) {
	if lr.exhausted {
		return "", os.EOF
	}
	nextCharIndex := 0;
	char := byte(0);

	skipLF := false;
	skipWhiteSpace := true;
	appendedLineBegin := false;
	isNewLine := true;
	isCommentLine := false;
	precedingBackslash := false;

	for {
		if lr.offset >= lr.limit {
			lr.limit, e = io.ReadFull(lr.reader, lr.buffer);
			lr.offset = 0;
			if e == os.EOF {
				lr.exhausted = true;
				if isCommentLine {
					return "", os.EOF
				}
				return string(lr.lineBuffer[0:nextCharIndex]), nil;
			}
			if e == io.ErrUnexpectedEOF {
				if isCommentLine {
					return "", os.EOF
				}
				continue;
			}
			if e != nil {
				lr.exhausted = true;
				return "", e;
			}
		}

		char = lr.buffer[lr.offset];
		lr.offset++;

		if skipLF {
			skipLF = false;
			if char == '\n' {
				continue
			}
		}

		if skipWhiteSpace {
			if char == ' ' || char == '\t' || char == '\f' {
				continue
			}
			if !appendedLineBegin && (char == '\r' || char == '\n') {
				continue
			}
			skipWhiteSpace = false;
			appendedLineBegin = false;
		}

		if isNewLine {
			isNewLine = false;
			if char == '#' || char == '!' {
				isCommentLine = true;
				continue;
			}
		}

		if char != '\n' && char != '\r' {
			lr.lineBuffer[nextCharIndex] = char;
			nextCharIndex++;
			if nextCharIndex == len(lr.lineBuffer) {
				newBuffer := make([]byte, len(lr.lineBuffer)*2);
				for i, x := range lr.lineBuffer {
					newBuffer[i] = x
				}
				lr.lineBuffer = newBuffer;
			}
			//flip the preceding backslash flag
			precedingBackslash = char == '\\' && !precedingBackslash;
		} else {
			// reached EOL
			if isCommentLine || nextCharIndex == 0 {
				isCommentLine = false;
				isNewLine = true;
				skipWhiteSpace = true;
				nextCharIndex = 0;
				continue;
			}
			if lr.offset >= lr.limit {
				lr.limit, e = io.ReadFull(lr.reader, lr.buffer);
				lr.offset = 0;
				if e == os.EOF || e == io.ErrUnexpectedEOF {
					lr.exhausted = true;
					return string(lr.lineBuffer[0:nextCharIndex]), nil;
				}
				if e != nil {
					lr.exhausted = true;
					return "", e;
				}
			}
			if precedingBackslash {
				nextCharIndex--;
				//skip the leading whitespace characters in following line
				skipWhiteSpace = true;
				appendedLineBegin = true;
				precedingBackslash = false;
				if char == '\r' {
					skipLF = true
				}
			} else {
				return string(lr.lineBuffer[0:nextCharIndex]), nil
			}
		}
	}

	return "", nil;
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"io"
	"io/ioutil"
	"log"
	"net"

	"golang.org/x/crypto/ssh"
)

type source int

const (
	client source = iota
	server
)

func (src source) String() string {
	switch src {
	case client:
		return "client"
	case server:
		return "server"
	default:
		return "unknown"
	}
}

func (src source) MarshalJSON() ([]byte, error) {
	return json.Marshal(src.String())
}

type channelLog struct {
	ChannelID int `json:"channel_id"`
}

type requestLog struct {
	Type      string `json:"type"`
	WantReply bool   `json:"want_reply"`
	Payload   string `json:"payload"`

	Accepted bool `json:"accepted"`
}

type logEntry interface {
	eventType() string
}

type globalRequestLog struct {
	requestLog

	Response string `json:"response"`
}

func (entry globalRequestLog) eventType() string {
	return "global_request"
}

type newChannelLog struct {
	Type      string `json:"type"`
	ExtraData string `json:"extra_data"`

	Accepted bool `json:"accepted"`
}

func (entry newChannelLog) eventType() string {
	return "new_channel"
}

type channelRequestLog struct {
	channelLog
	requestLog
}

func (entry channelRequestLog) eventType() string {
	return "channel_request"
}

type channelDataLog struct {
	channelLog
	Data string `json:"data"`
}

func (entry channelDataLog) eventType() string {
	return "channel_data"
}

type channelEOFLog struct {
	channelLog
}

func (entry channelEOFLog) eventType() string {
	return "channel_eof"
}

type channelCloseLog struct {
	channelLog
}

func (entry channelCloseLog) eventType() string {
	return "channel_close"
}

func logEvent(entry logEntry, src source) {
	jsonBytes, err := json.Marshal(struct {
		Source    string   `json:"source"`
		EventType string   `json:"event_type"`
		Event     logEntry `json:"event"`
	}{
		Source:    src.String(),
		EventType: entry.eventType(),
		Event:     entry,
	})
	if err != nil {
		panic(err)
	}
	log.Printf("%s", jsonBytes)
}

func streamReader(reader io.Reader) <-chan string {
	input := make(chan string)
	go func() {
		defer close(input)
		buffer := make([]byte, 256)
		for {
			n, err := reader.Read(buffer)
			if n > 0 {
				input <- string(buffer[:n])
			}
			if err != nil {
				if err != io.EOF {
					panic(err)
				}
				return
			}
		}
	}()
	return input
}

func handleChannel(channelID int, clientChannel ssh.Channel, clientRequests <-chan *ssh.Request, serverChannel ssh.Channel, serverRequests <-chan *ssh.Request) {
	clientInputStream := streamReader(clientChannel)
	serverInputStream := streamReader(serverChannel)
	serverErrorStream := streamReader(serverChannel.Stderr())

	for clientInputStream != nil || clientRequests != nil || serverInputStream != nil || serverRequests != nil {
		select {
		case clientInput, ok := <-clientInputStream:
			if !ok {
				if serverInputStream != nil {
					logEvent(channelEOFLog{
						channelLog: channelLog{
							ChannelID: channelID,
						},
					}, client)
					if err := serverChannel.CloseWrite(); err != nil {
						panic(err)
					}
				}
				clientInputStream = nil
				continue
			}
			logEvent(channelDataLog{
				channelLog: channelLog{
					ChannelID: channelID,
				},
				Data: clientInput,
			}, client)
			if _, err := serverChannel.Write([]byte(clientInput)); err != nil {
				panic(err)
			}
		case clientRequest, ok := <-clientRequests:
			if !ok {
				if serverRequests != nil {
					logEvent(channelCloseLog{
						channelLog: channelLog{
							ChannelID: channelID,
						},
					}, client)
					if err := serverChannel.Close(); err != nil {
						panic(err)
					}
				}
				clientRequests = nil
				continue
			}
			accepted, err := serverChannel.SendRequest(clientRequest.Type, clientRequest.WantReply, clientRequest.Payload)
			if err != nil {
				panic(err)
			}
			logEvent(channelRequestLog{
				channelLog: channelLog{
					ChannelID: channelID,
				},
				requestLog: requestLog{
					Type:      clientRequest.Type,
					WantReply: clientRequest.WantReply,
					Payload:   string(clientRequest.Payload),
					Accepted:  accepted,
				},
			}, client)
			if clientRequest.WantReply {
				if err := clientRequest.Reply(accepted, nil); err != nil {
					panic(err)
				}
			}
		case serverInput, ok := <-serverInputStream:
			if !ok {
				if clientInputStream != nil {
					logEvent(channelEOFLog{
						channelLog: channelLog{
							ChannelID: channelID,
						},
					}, server)
					if err := clientChannel.CloseWrite(); err != nil {
						panic(err)
					}
				}
				serverInputStream = nil
				continue
			}
			logEvent(channelDataLog{
				channelLog: channelLog{
					ChannelID: channelID,
				},
				Data: serverInput,
			}, server)
			if _, err := clientChannel.Write([]byte(serverInput)); err != nil {
				panic(err)
			}
		case serverError, ok := <-serverErrorStream:
			if !ok {
				log.Printf("Server error stream closed")
				serverErrorStream = nil
				continue
			}
			log.Printf("Server error: %q", serverError)
			if _, err := clientChannel.Stderr().Write([]byte(serverError)); err != nil {
				panic(err)
			}
		case serverRequest, ok := <-serverRequests:
			if !ok {
				if clientRequests != nil {
					logEvent(channelCloseLog{
						channelLog: channelLog{
							ChannelID: channelID,
						},
					}, server)
					if err := clientChannel.Close(); err != nil {
						panic(err)
					}
				}
				serverRequests = nil
				continue
			}
			accepted, err := clientChannel.SendRequest(serverRequest.Type, serverRequest.WantReply, serverRequest.Payload)
			if err != nil {
				panic(err)
			}
			logEvent(channelRequestLog{
				channelLog: channelLog{
					ChannelID: channelID,
				},
				requestLog: requestLog{
					Type:      serverRequest.Type,
					WantReply: serverRequest.WantReply,
					Payload:   string(serverRequest.Payload),
					Accepted:  accepted,
				},
			}, server)
			if serverRequest.WantReply {
				if err := serverRequest.Reply(accepted, nil); err != nil {
					panic(err)
				}
			}
		}
	}
}

func handleConn(clientConn net.Conn, sshServerConfig *ssh.ServerConfig, serverAddress string, clientKey ssh.Signer) {
	defer clientConn.Close()

	clientSSHConn, clientNewChannels, clientRequests, err := ssh.NewServerConn(clientConn, sshServerConfig)
	if err != nil {
		panic(err)
	}
	defer clientSSHConn.Close()

	serverConn, err := net.Dial("tcp", serverAddress)
	if err != nil {
		panic(err)
	}
	defer serverConn.Close()

	serverSSHConn, serverNewChannels, serverRequests, err := ssh.NewClientConn(serverConn, serverAddress, &ssh.ClientConfig{
		User:            clientSSHConn.User(),
		HostKeyCallback: ssh.InsecureIgnoreHostKey(),
		Auth: []ssh.AuthMethod{
			ssh.PublicKeys(clientKey),
		},
		ClientVersion: "SSH-2.0-OpenSSH_7.2",
	})
	if err != nil {
		panic(err)
	}
	defer serverSSHConn.Close()

	channelID := 0

	for clientNewChannels != nil || clientRequests != nil || serverNewChannels != nil || serverRequests != nil {
		select {
		case clientNewChannel, ok := <-clientNewChannels:
			if !ok {
				clientNewChannels = nil
				continue
			}
			serverChannel, serverChannelRequests, err := serverSSHConn.OpenChannel(clientNewChannel.ChannelType(), clientNewChannel.ExtraData())
			logEvent(newChannelLog{
				Type:      clientNewChannel.ChannelType(),
				ExtraData: string(clientNewChannel.ExtraData()),
				Accepted:  err == nil,
			}, client)
			if err != nil {
				if err, ok := err.(*ssh.OpenChannelError); ok {
					if err := clientNewChannel.Reject(err.Reason, err.Message); err != nil {
						panic(err)
					}
					continue
				}
				panic(err)
			}
			clientChannel, clientChannelRequests, err := clientNewChannel.Accept()
			if err != nil {
				panic(err)
			}
			go handleChannel(channelID, clientChannel, clientChannelRequests, serverChannel, serverChannelRequests)
		case clientRequest, ok := <-clientRequests:
			if !ok {
				clientRequests = nil
				continue
			}
			if clientRequest.Type == "no-more-sessions@openssh.com" {
				continue
			}
			accepted, response, err := serverSSHConn.SendRequest(clientRequest.Type, clientRequest.WantReply, clientRequest.Payload)
			if err != nil {
				panic(err)
			}
			logEvent(globalRequestLog{
				requestLog: requestLog{
					Type:      clientRequest.Type,
					WantReply: clientRequest.WantReply,
					Payload:   string(clientRequest.Payload),
					Accepted:  accepted,
				},
				Response: string(response),
			}, client)
			if err := clientRequest.Reply(accepted, response); err != nil {
				panic(err)
			}
		case serverNewChannel, ok := <-serverNewChannels:
			if !ok {
				serverNewChannels = nil
				continue
			}
			panic(serverNewChannel.ChannelType())
		case serverRequest, ok := <-serverRequests:
			if !ok {
				serverRequests = nil
				continue
			}
			accepted, response, err := clientSSHConn.SendRequest(serverRequest.Type, serverRequest.WantReply, serverRequest.Payload)
			logEvent(globalRequestLog{
				requestLog: requestLog{
					Type:      serverRequest.Type,
					WantReply: serverRequest.WantReply,
					Payload:   string(serverRequest.Payload),
					Accepted:  accepted,
				},
				Response: string(response),
			}, server)
			if err != nil {
				panic(err)
			}
			if err := serverRequest.Reply(accepted, response); err != nil {
				panic(err)
			}
		}
		channelID++
	}
}

func main() {
	listenAddress := flag.String("listen_address", "127.0.0.1:2022", "listen address")
	hostKeyFile := flag.String("host_key_file", "", "host key file")
	serverAddress := flag.String("server_address", "127.0.0.1:22", "server address")
	clientKeyFile := flag.String("client_key_file", "", "client key file")
	flag.Parse()
	if *listenAddress == "" {
		panic("listen address is required")
	}
	if *hostKeyFile == "" {
		panic("host key file is required")
	}
	if *serverAddress == "" {
		panic("server address is required")
	}
	if *clientKeyFile == "" {
		panic("client key file is required")
	}

	log.SetFlags(0)

	serverConfig := &ssh.ServerConfig{
		NoClientAuth:  true,
		ServerVersion: "SSH-2.0-OpenSSH_7.2",
	}
	hostKeyBytes, err := ioutil.ReadFile(*hostKeyFile)
	if err != nil {
		panic(err)
	}
	hostKey, err := ssh.ParsePrivateKey(hostKeyBytes)
	if err != nil {
		panic(err)
	}
	serverConfig.AddHostKey(hostKey)

	clientKeyBytes, err := ioutil.ReadFile(*clientKeyFile)
	if err != nil {
		panic(err)
	}
	clientKey, err := ssh.ParsePrivateKey(clientKeyBytes)
	if err != nil {
		panic(err)
	}

	listener, err := net.Listen("tcp", *listenAddress)
	if err != nil {
		panic(err)
	}
	defer listener.Close()
	for {
		conn, err := listener.Accept()
		if err != nil {
			panic(err)
		}
		go handleConn(conn, serverConfig, *serverAddress, clientKey)
	}
}
<commit_msg>Log stderr and no-more-sessions requests<commit_after>package main

import (
	"encoding/json"
	"flag"
	"io"
	"io/ioutil"
	"log"
	"net"

	"golang.org/x/crypto/ssh"
)

type source int

const (
	client source = iota
	server
)

func (src source) String() string {
	switch src {
	case client:
		return "client"
	case server:
		return "server"
	default:
		return "unknown"
	}
}

func (src source) MarshalJSON() ([]byte, error) {
	return json.Marshal(src.String())
}

type channelLog struct {
	ChannelID int `json:"channel_id"`
}

type requestLog struct {
	Type      string `json:"type"`
	WantReply bool   `json:"want_reply"`
	Payload   string `json:"payload"`

	Accepted bool `json:"accepted"`
}

type logEntry interface {
	eventType() string
}

type globalRequestLog struct {
	requestLog

	Response string `json:"response"`
}

func (entry globalRequestLog) eventType() string {
	return "global_request"
}

type newChannelLog struct {
	Type      string `json:"type"`
	ExtraData string `json:"extra_data"`

	Accepted bool `json:"accepted"`
}

func (entry newChannelLog) eventType() string {
	return "new_channel"
}

type channelRequestLog struct {
	channelLog
	requestLog
}

func (entry channelRequestLog) eventType() string {
	return "channel_request"
}

type channelDataLog struct {
	channelLog
	Data string `json:"data"`
}

func (entry channelDataLog) eventType() string {
	return "channel_data"
}

type channelErrorLog struct {
	channelLog
	Data string `json:"data"`
}

func (entry channelErrorLog) eventType() string {
	return "channel_error"
}

type channelEOFLog struct {
	channelLog
}

func (entry channelEOFLog) eventType() string {
	return "channel_eof"
}

type channelCloseLog struct {
	channelLog
}

func (entry channelCloseLog) eventType() string {
	return "channel_close"
}

func logEvent(entry logEntry, src source) {
	jsonBytes, err := json.Marshal(struct {
		Source    string   `json:"source"`
		EventType string   `json:"event_type"`
		Event     logEntry `json:"event"`
	}{
		Source:    src.String(),
		EventType: entry.eventType(),
		Event:     entry,
	})
	if err != nil {
		panic(err)
	}
	log.Printf("%s", jsonBytes)
}

func streamReader(reader io.Reader) <-chan string {
	input := make(chan string)
	go func() {
		defer close(input)
		buffer := make([]byte, 256)
		for {
			n, err := reader.Read(buffer)
			if n > 0 {
				input <- string(buffer[:n])
			}
			if err != nil {
				if err != io.EOF {
					panic(err)
				}
				return
			}
		}
	}()
	return input
}

func handleChannel(channelID int, clientChannel ssh.Channel, clientRequests <-chan *ssh.Request, serverChannel ssh.Channel, serverRequests <-chan *ssh.Request) {
	clientInputStream := streamReader(clientChannel)
	serverInputStream := streamReader(serverChannel)
	serverErrorStream := streamReader(serverChannel.Stderr())

	for clientInputStream != nil || clientRequests != nil || serverInputStream != nil || serverRequests != nil {
		select {
		case clientInput, ok := <-clientInputStream:
			if !ok {
				if serverInputStream != nil {
					logEvent(channelEOFLog{
						channelLog: channelLog{
							ChannelID: channelID,
						},
					}, client)
					if err := serverChannel.CloseWrite(); err != nil {
						panic(err)
					}
				}
				clientInputStream = nil
				continue
			}
			logEvent(channelDataLog{
				channelLog: channelLog{
					ChannelID: channelID,
				},
				Data: clientInput,
			}, client)
			if _, err := serverChannel.Write([]byte(clientInput)); err != nil {
				panic(err)
			}
		case clientRequest, ok := <-clientRequests:
			if !ok {
				if serverRequests != nil {
					logEvent(channelCloseLog{
						channelLog: channelLog{
							ChannelID: channelID,
						},
					}, client)
					if err := serverChannel.Close(); err != nil {
						panic(err)
					}
				}
				clientRequests = nil
				continue
			}
			accepted, err := serverChannel.SendRequest(clientRequest.Type, clientRequest.WantReply, clientRequest.Payload)
			if err != nil {
				panic(err)
			}
			logEvent(channelRequestLog{
				channelLog: channelLog{
					ChannelID: channelID,
				},
				requestLog: requestLog{
					Type:      clientRequest.Type,
					WantReply: clientRequest.WantReply,
					Payload:   string(clientRequest.Payload),
					Accepted:  accepted,
				},
			}, client)
			if clientRequest.WantReply {
				if err := clientRequest.Reply(accepted, nil); err != nil {
					panic(err)
				}
			}
		case serverInput, ok := <-serverInputStream:
			if !ok {
				if clientInputStream != nil {
					logEvent(channelEOFLog{
						channelLog: channelLog{
							ChannelID: channelID,
						},
					}, server)
					if err := clientChannel.CloseWrite(); err != nil {
						panic(err)
					}
				}
				serverInputStream = nil
				continue
			}
			logEvent(channelDataLog{
				channelLog: channelLog{
					ChannelID: channelID,
				},
				Data: serverInput,
			}, server)
			if _, err := clientChannel.Write([]byte(serverInput)); err != nil {
				panic(err)
			}
		case serverError, ok := <-serverErrorStream:
			if !ok {
				serverErrorStream = nil
				continue
			}
			logEvent(channelErrorLog{
				channelLog: channelLog{
					ChannelID: channelID,
				},
				Data: serverError,
			}, server)
			if _, err := clientChannel.Stderr().Write([]byte(serverError)); err != nil {
				panic(err)
			}
		case serverRequest, ok := <-serverRequests:
			if !ok {
				if clientRequests != nil {
					logEvent(channelCloseLog{
						channelLog: channelLog{
							ChannelID: channelID,
						},
					}, server)
					if err := clientChannel.Close(); err != nil {
						panic(err)
					}
				}
				serverRequests = nil
				continue
			}
			accepted, err := clientChannel.SendRequest(serverRequest.Type, serverRequest.WantReply, serverRequest.Payload)
			if err != nil {
				panic(err)
			}
			logEvent(channelRequestLog{
				channelLog: channelLog{
					ChannelID: channelID,
				},
				requestLog: requestLog{
					Type:      serverRequest.Type,
					WantReply: serverRequest.WantReply,
					Payload:   string(serverRequest.Payload),
					Accepted:  accepted,
				},
			}, server)
			if serverRequest.WantReply {
				if err := serverRequest.Reply(accepted, nil); err != nil {
					panic(err)
				}
			}
		}
	}
}

func handleConn(clientConn net.Conn, sshServerConfig *ssh.ServerConfig, serverAddress string, clientKey ssh.Signer) {
	defer clientConn.Close()

	clientSSHConn, clientNewChannels, clientRequests, err := ssh.NewServerConn(clientConn, sshServerConfig)
	if err != nil {
		panic(err)
	}
	defer clientSSHConn.Close()

	serverConn, err := net.Dial("tcp", serverAddress)
	if err != nil {
		panic(err)
	}
	defer serverConn.Close()

	serverSSHConn, serverNewChannels, serverRequests, err := ssh.NewClientConn(serverConn, serverAddress, &ssh.ClientConfig{
		User:            clientSSHConn.User(),
		HostKeyCallback: ssh.InsecureIgnoreHostKey(),
		Auth: []ssh.AuthMethod{
			ssh.PublicKeys(clientKey),
		},
		ClientVersion: "SSH-2.0-OpenSSH_7.2",
	})
	if err != nil {
		panic(err)
	}
	defer serverSSHConn.Close()

	channelID := 0

	for clientNewChannels != nil || clientRequests != nil || serverNewChannels != nil || serverRequests != nil {
		select {
		case clientNewChannel, ok := <-clientNewChannels:
			if !ok {
				clientNewChannels = nil
				continue
			}
			serverChannel, serverChannelRequests, err := serverSSHConn.OpenChannel(clientNewChannel.ChannelType(), clientNewChannel.ExtraData())
			logEvent(newChannelLog{
				Type:      clientNewChannel.ChannelType(),
				ExtraData: string(clientNewChannel.ExtraData()),
				Accepted:  err == nil,
			}, client)
			if err != nil {
				if err, ok := err.(*ssh.OpenChannelError); ok {
					if err := clientNewChannel.Reject(err.Reason, err.Message); err != nil {
						panic(err)
					}
					continue
				}
				panic(err)
			}
			clientChannel, clientChannelRequests, err := clientNewChannel.Accept()
			if err != nil {
				panic(err)
			}
			go handleChannel(channelID, clientChannel, clientChannelRequests, serverChannel, serverChannelRequests)
		case clientRequest, ok := <-clientRequests:
			if !ok {
				clientRequests = nil
				continue
			}
			if clientRequest.Type == "no-more-sessions@openssh.com" {
				logEvent(globalRequestLog{
					requestLog: requestLog{
						Type:      clientRequest.Type,
						WantReply: clientRequest.WantReply,
						Payload:   string(clientRequest.Payload),
						Accepted:  clientRequest.WantReply,
					},
					Response: string([]byte{}),
				}, client)
				continue
			}
			accepted, response, err := serverSSHConn.SendRequest(clientRequest.Type, clientRequest.WantReply, clientRequest.Payload)
			if err != nil {
				panic(err)
			}
			logEvent(globalRequestLog{
				requestLog: requestLog{
					Type:      clientRequest.Type,
					WantReply: clientRequest.WantReply,
					Payload:   string(clientRequest.Payload),
					Accepted:  accepted,
				},
				Response: string(response),
			}, client)
			if err := clientRequest.Reply(accepted, response); err != nil {
				panic(err)
			}
		case serverNewChannel, ok := <-serverNewChannels:
			if !ok {
				serverNewChannels = nil
				continue
			}
			panic(serverNewChannel.ChannelType())
		case serverRequest, ok := <-serverRequests:
			if !ok {
				serverRequests = nil
				continue
			}
			accepted, response, err := clientSSHConn.SendRequest(serverRequest.Type, serverRequest.WantReply, serverRequest.Payload)
			logEvent(globalRequestLog{
				requestLog: requestLog{
					Type:      serverRequest.Type,
					WantReply: serverRequest.WantReply,
					Payload:   string(serverRequest.Payload),
					Accepted:  accepted,
				},
				Response: string(response),
			}, server)
			if err != nil {
				panic(err)
			}
			if err := serverRequest.Reply(accepted, response); err != nil {
				panic(err)
			}
		}
		channelID++
	}
}

func main() {
	listenAddress := flag.String("listen_address", "127.0.0.1:2022", "listen address")
	hostKeyFile := flag.String("host_key_file", "", "host key file")
	serverAddress := flag.String("server_address", "127.0.0.1:22", "server address")
	clientKeyFile := flag.String("client_key_file", "", "client key file")
	flag.Parse()
	if *listenAddress == "" {
		panic("listen address is required")
	}
	if *hostKeyFile == "" {
		panic("host key file is required")
	}
	if *serverAddress == "" {
		panic("server address is required")
	}
	if *clientKeyFile == "" {
		panic("client key file is required")
	}

	log.SetFlags(0)

	serverConfig := &ssh.ServerConfig{
		NoClientAuth:  true,
		ServerVersion: "SSH-2.0-OpenSSH_7.2",
	}
	hostKeyBytes, err := ioutil.ReadFile(*hostKeyFile)
	if err != nil {
		panic(err)
	}
	hostKey, err := ssh.ParsePrivateKey(hostKeyBytes)
	if err != nil {
		panic(err)
	}
	serverConfig.AddHostKey(hostKey)

	clientKeyBytes, err := ioutil.ReadFile(*clientKeyFile)
	if err != nil {
		panic(err)
	}
	clientKey, err := ssh.ParsePrivateKey(clientKeyBytes)
	if err != nil {
		panic(err)
	}

	listener, err := net.Listen("tcp", *listenAddress)
	if err != nil {
		panic(err)
	}
	defer listener.Close()
	for {
		conn, err := listener.Accept()
		if err != nil {
			panic(err)
		}
		go handleConn(conn, serverConfig, *serverAddress, clientKey)
	}
}
<|endoftext|>


<commit_before>package operations_test

import (
	"testing"

	"github.com/omise/omise-go"
	"github.com/omise/omise-go/internal/testutil"
	. "github.com/omise/omise-go/operations"
	a "github.com/stretchr/testify/assert"
)

func TestCard(t *testing.T) {
	client, e := testutil.NewClient()
	if !a.NoError(t, e) {
		return
	}

	create := &CreateCustomer{
		Email:       "chakrit@omise.co",
		Description: "Omise",
		Card:        "",
	}

	customer := &omise.Customer{}
	if e := client.Do(customer, create); !a.NoError(t, e) {
		return
	}

	// list empty collection
	list := &ListCards{CustomerID: customer.ID}
	cards := &omise.CardList{}
	if e := client.Do(cards, list); !a.NoError(t, e) {
		return
	}

	if !a.NotNil(t, cards) {
		return
	}

	a.Len(t, cards.Data, 0)

	// add some cards
	tok1, tok2 := &omise.Token{}, &omise.Token{}
	if e := client.Do(tok1, CreateTokenOp); !a.NoError(t, e) {
		return
	} else if e := client.Do(tok2, CreateTokenOp); !a.NoError(t, e) {
		return
	}

	update1 := &UpdateCustomer{CustomerID: customer.ID, Card: tok1.ID}
	update2 := &UpdateCustomer{CustomerID: customer.ID, Card: tok2.ID}
	if e := client.Do(customer, update1); !a.NoError(t, e) {
		return
	} else if e := client.Do(customer, update2); !a.NoError(t, e) {
		return
	}

	// see added cards
	if e := client.Do(cards, list); !a.NoError(t, e) {
		return
	}

	a.Len(t, cards.Data, 2)

	// retreive added cards
	card := &omise.Card{}
	retreive := &RetreiveCard{CustomerID: customer.ID, CardID: cards.Data[0].ID}
	if e := client.Do(card, retreive); !a.NoError(t, e) {
		return
	}

	a.Equal(t, cards.Data[0].ID, card.ID)
	a.Equal(t, cards.Data[0].LastDigits, card.LastDigits)

	// remove cards
	del1, del2 := &omise.Deletion{}, &omise.Deletion{}
	if e := client.Do(del1, &DestroyCard{CustomerID: customer.ID, CardID: cards.Data[0].ID}); !a.NoError(t, e) {
		return
	} else if e := client.Do(del2, &DestroyCard{CustomerID: customer.ID, CardID: cards.Data[1].ID}); !a.NoError(t, e) {
		return
	}

	a.Equal(t, cards.Data[0].ID, del1.ID)
	a.Equal(t, cards.Data[1].ID, del2.ID)
	a.True(t, del1.Deleted)
	a.True(t, del2.Deleted)

	// list should be empty again
	if e := client.Do(cards, list); !a.NoError(t, e) {
		return
	}

	a.Len(t, cards.Data, 0)
}
<commit_msg>Fix card list test.<commit_after>package operations_test

import (
	"testing"

	"github.com/omise/omise-go"
	"github.com/omise/omise-go/internal/testutil"
	. "github.com/omise/omise-go/operations"
	a "github.com/stretchr/testify/assert"
)

func TestCard(t *testing.T) {
	client, e := testutil.NewClient()
	if !a.NoError(t, e) {
		return
	}

	create := &CreateCustomer{
		Email:       "chakrit@omise.co",
		Description: "Omise",
		Card:        "",
	}

	customer := &omise.Customer{}
	if e := client.Do(customer, create); !a.NoError(t, e) {
		return
	}
	defer client.Do(nil, &DestroyCustomer{customer.ID})

	// list empty collection
	list := &ListCards{CustomerID: customer.ID}
	cards := &omise.CardList{}
	if e := client.Do(cards, list); !a.NoError(t, e) {
		return
	}

	if !a.NotNil(t, cards) {
		return
	}

	a.Len(t, cards.Data, 0)

	// add some cards
	tok1, tok2 := &omise.Token{}, &omise.Token{}
	if e := client.Do(tok1, CreateTokenOp); !a.NoError(t, e) {
		return
	} else if e := client.Do(tok2, CreateTokenOp); !a.NoError(t, e) {
		return
	}

	update1 := &UpdateCustomer{CustomerID: customer.ID, Card: tok1.ID}
	update2 := &UpdateCustomer{CustomerID: customer.ID, Card: tok2.ID}
	if e := client.Do(customer, update1); !a.NoError(t, e) {
		return
	} else if e := client.Do(customer, update2); !a.NoError(t, e) {
		return
	}

	// see added cards (using pagination API to call twice)
	firstHalf := &omise.CardList{}
	list.Offset = 0
	list.Limit = 1
	if e := client.Do(firstHalf, list); !a.NoError(t, e) {
		return
	}

	a.Len(t, firstHalf.Data, 1)

	secondHalf := &omise.CardList{}
	list.Offset = 1
	list.Limit = 1
	if e := client.Do(secondHalf, list); !a.NoError(t, e) {
		return
	}

	a.Len(t, secondHalf.Data, 1)

	cards = &omise.CardList{
		List: omise.List{Offset: 0, Limit: 0},
		Data: append(firstHalf.Data, secondHalf.Data...),
	}
	a.Len(t, cards.Data, 2)

	// retreive added cards
	card := &omise.Card{}
	retreive := &RetreiveCard{CustomerID: customer.ID, CardID: cards.Data[0].ID}
	if e := client.Do(card, retreive); !a.NoError(t, e) {
		return
	}

	a.Equal(t, cards.Data[0].ID, card.ID)
	a.Equal(t, cards.Data[0].LastDigits, card.LastDigits)

	// remove cards
	del1, del2 := &omise.Deletion{}, &omise.Deletion{}
	if e := client.Do(del1, &DestroyCard{CustomerID: customer.ID, CardID: cards.Data[0].ID}); !a.NoError(t, e) {
		return
	} else if e := client.Do(del2, &DestroyCard{CustomerID: customer.ID, CardID: cards.Data[1].ID}); !a.NoError(t, e) {
		return
	}

	a.Equal(t, cards.Data[0].ID, del1.ID)
	a.Equal(t, cards.Data[1].ID, del2.ID)
	a.True(t, del1.Deleted)
	a.True(t, del2.Deleted)

	// list should be empty again
	if e := client.Do(cards, list); !a.NoError(t, e) {
		return
	}

	a.Len(t, cards.Data, 0)
}
<|endoftext|>


<commit_before>package libp2p

// This file contains all the default configuration options.

import (
	"crypto/rand"

	"github.com/libp2p/go-libp2p/p2p/muxer/yamux"
	"github.com/libp2p/go-libp2p/p2p/net/connmgr"
	"github.com/libp2p/go-libp2p/p2p/security/noise"
	tls "github.com/libp2p/go-libp2p/p2p/security/tls"
	quic "github.com/libp2p/go-libp2p/p2p/transport/quic"
	"github.com/libp2p/go-libp2p/p2p/transport/tcp"
	ws "github.com/libp2p/go-libp2p/p2p/transport/websocket"

	"github.com/libp2p/go-libp2p-core/crypto"

	"github.com/libp2p/go-libp2p-peerstore/pstoremem"
	rcmgr "github.com/libp2p/go-libp2p-resource-manager"
	"github.com/multiformats/go-multiaddr"
)

// DefaultSecurity is the default security option.
//
// Useful when you want to extend, but not replace, the supported transport
// security protocols.
var DefaultSecurity = ChainOptions(
	Security(noise.ID, noise.New),
	Security(tls.ID, tls.New),
)

// DefaultMuxers configures libp2p to use the stream connection multiplexers.
//
// Use this option when you want to *extend* the set of multiplexers used by
// libp2p instead of replacing them.
var DefaultMuxers = Muxer("/yamux/1.0.0", yamux.DefaultTransport)

// DefaultTransports are the default libp2p transports.
//
// Use this option when you want to *extend* the set of transports used by
// libp2p instead of replacing them.
var DefaultTransports = ChainOptions(
	Transport(tcp.NewTCPTransport),
	Transport(quic.NewTransport),
	Transport(ws.New),
)

// DefaultPeerstore configures libp2p to use the default peerstore.
var DefaultPeerstore Option = func(cfg *Config) error {
	ps, err := pstoremem.NewPeerstore()
	if err != nil {
		return err
	}
	return cfg.Apply(Peerstore(ps))
}

// RandomIdentity generates a random identity. (default behaviour)
var RandomIdentity = func(cfg *Config) error {
	priv, _, err := crypto.GenerateKeyPairWithReader(crypto.RSA, 2048, rand.Reader)
	if err != nil {
		return err
	}
	return cfg.Apply(Identity(priv))
}

// DefaultListenAddrs configures libp2p to use default listen address.
var DefaultListenAddrs = func(cfg *Config) error {
	defaultIP4ListenAddr, err := multiaddr.NewMultiaddr("/ip4/0.0.0.0/tcp/0")
	if err != nil {
		return err
	}

	defaultIP6ListenAddr, err := multiaddr.NewMultiaddr("/ip6/::/tcp/0")
	if err != nil {
		return err
	}
	return cfg.Apply(ListenAddrs(
		defaultIP4ListenAddr,
		defaultIP6ListenAddr,
	))
}

// DefaultEnableRelay enables relay dialing and listening by default.
var DefaultEnableRelay = func(cfg *Config) error {
	return cfg.Apply(EnableRelay())
}

var DefaultResourceManager = func(cfg *Config) error {
	// Default memory limit: 1/8th of total memory, minimum 128MB, maximum 1GB
	limits := rcmgr.DefaultLimits
	SetDefaultServiceLimits(&limits)
	mgr, err := rcmgr.NewResourceManager(rcmgr.NewFixedLimiter(limits.AutoScale()))
	if err != nil {
		return err
	}

	return cfg.Apply(ResourceManager(mgr))
}

// DefaultConnectionManager creates a default connection manager
var DefaultConnectionManager = func(cfg *Config) error {
	mgr, err := connmgr.NewConnManager(160, 192)
	if err != nil {
		return err
	}

	return cfg.Apply(ConnectionManager(mgr))
}

// Complete list of default options and when to fallback on them.
//
// Please *DON'T* specify default options any other way. Putting this all here
// makes tracking defaults *much* easier.
var defaults = []struct {
	fallback func(cfg *Config) bool
	opt      Option
}{
	{
		fallback: func(cfg *Config) bool { return cfg.Transports == nil && cfg.ListenAddrs == nil },
		opt:      DefaultListenAddrs,
	},
	{
		fallback: func(cfg *Config) bool { return cfg.Transports == nil },
		opt:      DefaultTransports,
	},
	{
		fallback: func(cfg *Config) bool { return cfg.Muxers == nil },
		opt:      DefaultMuxers,
	},
	{
		fallback: func(cfg *Config) bool { return !cfg.Insecure && cfg.SecurityTransports == nil },
		opt:      DefaultSecurity,
	},
	{
		fallback: func(cfg *Config) bool { return cfg.PeerKey == nil },
		opt:      RandomIdentity,
	},
	{
		fallback: func(cfg *Config) bool { return cfg.Peerstore == nil },
		opt:      DefaultPeerstore,
	},
	{
		fallback: func(cfg *Config) bool { return !cfg.RelayCustom },
		opt:      DefaultEnableRelay,
	},
	{
		fallback: func(cfg *Config) bool { return cfg.ResourceManager == nil },
		opt:      DefaultResourceManager,
	},
	{
		fallback: func(cfg *Config) bool { return cfg.ConnManager == nil },
		opt:      DefaultConnectionManager,
	},
}

// Defaults configures libp2p to use the default options. Can be combined with
// other options to *extend* the default options.
var Defaults Option = func(cfg *Config) error {
	for _, def := range defaults {
		if err := cfg.Apply(def.opt); err != nil {
			return err
		}
	}
	return nil
}

// FallbackDefaults applies default options to the libp2p node if and only if no
// other relevant options have been applied. will be appended to the options
// passed into New.
var FallbackDefaults Option = func(cfg *Config) error {
	for _, def := range defaults {
		if !def.fallback(cfg) {
			continue
		}
		if err := cfg.Apply(def.opt); err != nil {
			return err
		}
	}
	return nil
}
<commit_msg>change the default key type to Ed25519 (#1576)<commit_after>package libp2p

// This file contains all the default configuration options.

import (
	"crypto/rand"

	"github.com/libp2p/go-libp2p/p2p/muxer/yamux"
	"github.com/libp2p/go-libp2p/p2p/net/connmgr"
	"github.com/libp2p/go-libp2p/p2p/security/noise"
	tls "github.com/libp2p/go-libp2p/p2p/security/tls"
	quic "github.com/libp2p/go-libp2p/p2p/transport/quic"
	"github.com/libp2p/go-libp2p/p2p/transport/tcp"
	ws "github.com/libp2p/go-libp2p/p2p/transport/websocket"

	"github.com/libp2p/go-libp2p-core/crypto"

	"github.com/libp2p/go-libp2p-peerstore/pstoremem"
	rcmgr "github.com/libp2p/go-libp2p-resource-manager"
	"github.com/multiformats/go-multiaddr"
)

// DefaultSecurity is the default security option.
//
// Useful when you want to extend, but not replace, the supported transport
// security protocols.
var DefaultSecurity = ChainOptions(
	Security(noise.ID, noise.New),
	Security(tls.ID, tls.New),
)

// DefaultMuxers configures libp2p to use the stream connection multiplexers.
//
// Use this option when you want to *extend* the set of multiplexers used by
// libp2p instead of replacing them.
var DefaultMuxers = Muxer("/yamux/1.0.0", yamux.DefaultTransport)

// DefaultTransports are the default libp2p transports.
//
// Use this option when you want to *extend* the set of transports used by
// libp2p instead of replacing them.
var DefaultTransports = ChainOptions(
	Transport(tcp.NewTCPTransport),
	Transport(quic.NewTransport),
	Transport(ws.New),
)

// DefaultPeerstore configures libp2p to use the default peerstore.
var DefaultPeerstore Option = func(cfg *Config) error {
	ps, err := pstoremem.NewPeerstore()
	if err != nil {
		return err
	}
	return cfg.Apply(Peerstore(ps))
}

// RandomIdentity generates a random identity. (default behaviour)
var RandomIdentity = func(cfg *Config) error {
	priv, _, err := crypto.GenerateEd25519Key(rand.Reader)
	if err != nil {
		return err
	}
	return cfg.Apply(Identity(priv))
}

// DefaultListenAddrs configures libp2p to use default listen address.
var DefaultListenAddrs = func(cfg *Config) error {
	defaultIP4ListenAddr, err := multiaddr.NewMultiaddr("/ip4/0.0.0.0/tcp/0")
	if err != nil {
		return err
	}

	defaultIP6ListenAddr, err := multiaddr.NewMultiaddr("/ip6/::/tcp/0")
	if err != nil {
		return err
	}
	return cfg.Apply(ListenAddrs(
		defaultIP4ListenAddr,
		defaultIP6ListenAddr,
	))
}

// DefaultEnableRelay enables relay dialing and listening by default.
var DefaultEnableRelay = func(cfg *Config) error {
	return cfg.Apply(EnableRelay())
}

var DefaultResourceManager = func(cfg *Config) error {
	// Default memory limit: 1/8th of total memory, minimum 128MB, maximum 1GB
	limits := rcmgr.DefaultLimits
	SetDefaultServiceLimits(&limits)
	mgr, err := rcmgr.NewResourceManager(rcmgr.NewFixedLimiter(limits.AutoScale()))
	if err != nil {
		return err
	}

	return cfg.Apply(ResourceManager(mgr))
}

// DefaultConnectionManager creates a default connection manager
var DefaultConnectionManager = func(cfg *Config) error {
	mgr, err := connmgr.NewConnManager(160, 192)
	if err != nil {
		return err
	}

	return cfg.Apply(ConnectionManager(mgr))
}

// Complete list of default options and when to fallback on them.
//
// Please *DON'T* specify default options any other way. Putting this all here
// makes tracking defaults *much* easier.
var defaults = []struct {
	fallback func(cfg *Config) bool
	opt      Option
}{
	{
		fallback: func(cfg *Config) bool { return cfg.Transports == nil && cfg.ListenAddrs == nil },
		opt:      DefaultListenAddrs,
	},
	{
		fallback: func(cfg *Config) bool { return cfg.Transports == nil },
		opt:      DefaultTransports,
	},
	{
		fallback: func(cfg *Config) bool { return cfg.Muxers == nil },
		opt:      DefaultMuxers,
	},
	{
		fallback: func(cfg *Config) bool { return !cfg.Insecure && cfg.SecurityTransports == nil },
		opt:      DefaultSecurity,
	},
	{
		fallback: func(cfg *Config) bool { return cfg.PeerKey == nil },
		opt:      RandomIdentity,
	},
	{
		fallback: func(cfg *Config) bool { return cfg.Peerstore == nil },
		opt:      DefaultPeerstore,
	},
	{
		fallback: func(cfg *Config) bool { return !cfg.RelayCustom },
		opt:      DefaultEnableRelay,
	},
	{
		fallback: func(cfg *Config) bool { return cfg.ResourceManager == nil },
		opt:      DefaultResourceManager,
	},
	{
		fallback: func(cfg *Config) bool { return cfg.ConnManager == nil },
		opt:      DefaultConnectionManager,
	},
}

// Defaults configures libp2p to use the default options. Can be combined with
// other options to *extend* the default options.
var Defaults Option = func(cfg *Config) error {
	for _, def := range defaults {
		if err := cfg.Apply(def.opt); err != nil {
			return err
		}
	}
	return nil
}

// FallbackDefaults applies default options to the libp2p node if and only if no
// other relevant options have been applied. will be appended to the options
// passed into New.
var FallbackDefaults Option = func(cfg *Config) error {
	for _, def := range defaults {
		if !def.fallback(cfg) {
			continue
		}
		if err := cfg.Apply(def.opt); err != nil {
			return err
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package rest

import (
	"fmt"
	"net/url"
	"regexp"
	"testing"
)

func routes() []*Route {
	// simulate the routes of a real but reasonable app.
	// 6 + 10 * (5 + 2) + 1 = 77 routes
	routePaths := []string{
		"/",
		"/signin",
		"/signout",
		"/profile",
		"/settings",
		"/upload/*file",
	}
	for i := 0; i < 10; i++ {
		for j := 0; j < 5; j++ {
			routePaths = append(routePaths, fmt.Sprintf("/resource%d/:id/property%d", i, j))
		}
		routePaths = append(routePaths, fmt.Sprintf("/resource%d/:id", i))
		routePaths = append(routePaths, fmt.Sprintf("/resource%d", i))
	}
	routePaths = append(routePaths, "/*")

	routes := []*Route{}
	for _, path := range routePaths {
		routes = append(routes, &Route{
			HttpMethod: "GET",
			PathExp:    path,
		})
	}
	return routes
}

func requestUrls() []*url.URL {
	// simulate a few requests
	urlStrs := []string{
		"http://example.org/",
		"http://example.org/resource9/123",
		"http://example.org/resource9/123/property1",
		"http://example.org/doesnotexist",
	}
	urlObjs := []*url.URL{}
	for _, urlStr := range urlStrs {
		urlObj, _ := url.Parse(urlStr)
		urlObjs = append(urlObjs, urlObj)
	}
	return urlObjs
}

func BenchmarkNoCompression(b *testing.B) {

	b.StopTimer()

	r := router{
		routes:                 routes(),
		disableTrieCompression: true,
	}
	r.start()
	urlObjs := requestUrls()

	b.StartTimer()

	for i := 0; i < b.N; i++ {
		for _, urlObj := range urlObjs {
			r.findRouteFromURL("GET", urlObj)
		}
	}
}

func BenchmarkCompression(b *testing.B) {

	b.StopTimer()

	r := router{
		routes: routes(),
	}
	r.start()
	urlObjs := requestUrls()

	b.StartTimer()

	for i := 0; i < b.N; i++ {
		for _, urlObj := range urlObjs {
			r.findRouteFromURL("GET", urlObj)
		}
	}
}

func BenchmarkRegExpLoop(b *testing.B) {
	// reference benchmark using the usual RegExps + Loop strategy

	b.StopTimer()

	routes := routes()
	urlObjs := requestUrls()

	// build the route regexps
	r1, err := regexp.Compile(":[^/\\.]*")
	if err != nil {
		panic(err)
	}
	r2, err := regexp.Compile("\\*.*")
	if err != nil {
		panic(err)
	}
	routeRegexps := []regexp.Regexp{}
	for _, route := range routes {

		// generate the regexp string
		regStr := r2.ReplaceAllString(route.PathExp, "([^/\\.]+)")
		regStr = r1.ReplaceAllString(regStr, "(.+)")
		regStr = "^" + regStr + "$"

		// compile it
		reg, err := regexp.Compile(regStr)
		if err != nil {
			panic(err)
		}

		routeRegexps = append(routeRegexps, *reg)
	}

	b.StartTimer()

	for i := 0; i < b.N; i++ {
		// do it for a few urls
		for _, urlObj := range urlObjs {
			// stop at the first route that matches
			for index, reg := range routeRegexps {
				if reg.FindAllString(urlObj.Path, 1) != nil {
					_ = routes[index]
					break
				}
			}
		}
	}
}
<commit_msg>Don't copy regexp.Regexp during range<commit_after>package rest

import (
	"fmt"
	"net/url"
	"regexp"
	"testing"
)

func routes() []*Route {
	// simulate the routes of a real but reasonable app.
	// 6 + 10 * (5 + 2) + 1 = 77 routes
	routePaths := []string{
		"/",
		"/signin",
		"/signout",
		"/profile",
		"/settings",
		"/upload/*file",
	}
	for i := 0; i < 10; i++ {
		for j := 0; j < 5; j++ {
			routePaths = append(routePaths, fmt.Sprintf("/resource%d/:id/property%d", i, j))
		}
		routePaths = append(routePaths, fmt.Sprintf("/resource%d/:id", i))
		routePaths = append(routePaths, fmt.Sprintf("/resource%d", i))
	}
	routePaths = append(routePaths, "/*")

	routes := []*Route{}
	for _, path := range routePaths {
		routes = append(routes, &Route{
			HttpMethod: "GET",
			PathExp:    path,
		})
	}
	return routes
}

func requestUrls() []*url.URL {
	// simulate a few requests
	urlStrs := []string{
		"http://example.org/",
		"http://example.org/resource9/123",
		"http://example.org/resource9/123/property1",
		"http://example.org/doesnotexist",
	}
	urlObjs := []*url.URL{}
	for _, urlStr := range urlStrs {
		urlObj, _ := url.Parse(urlStr)
		urlObjs = append(urlObjs, urlObj)
	}
	return urlObjs
}

func BenchmarkNoCompression(b *testing.B) {

	b.StopTimer()

	r := router{
		routes:                 routes(),
		disableTrieCompression: true,
	}
	r.start()
	urlObjs := requestUrls()

	b.StartTimer()

	for i := 0; i < b.N; i++ {
		for _, urlObj := range urlObjs {
			r.findRouteFromURL("GET", urlObj)
		}
	}
}

func BenchmarkCompression(b *testing.B) {

	b.StopTimer()

	r := router{
		routes: routes(),
	}
	r.start()
	urlObjs := requestUrls()

	b.StartTimer()

	for i := 0; i < b.N; i++ {
		for _, urlObj := range urlObjs {
			r.findRouteFromURL("GET", urlObj)
		}
	}
}

func BenchmarkRegExpLoop(b *testing.B) {
	// reference benchmark using the usual RegExps + Loop strategy

	b.StopTimer()

	routes := routes()
	urlObjs := requestUrls()

	// build the route regexps
	r1, err := regexp.Compile(":[^/\\.]*")
	if err != nil {
		panic(err)
	}
	r2, err := regexp.Compile("\\*.*")
	if err != nil {
		panic(err)
	}
	routeRegexps := []*regexp.Regexp{}
	for _, route := range routes {

		// generate the regexp string
		regStr := r2.ReplaceAllString(route.PathExp, "([^/\\.]+)")
		regStr = r1.ReplaceAllString(regStr, "(.+)")
		regStr = "^" + regStr + "$"

		// compile it
		reg, err := regexp.Compile(regStr)
		if err != nil {
			panic(err)
		}

		routeRegexps = append(routeRegexps, reg)
	}

	b.StartTimer()

	for i := 0; i < b.N; i++ {
		// do it for a few urls
		for _, urlObj := range urlObjs {
			// stop at the first route that matches
			for index, reg := range routeRegexps {
				if reg.FindAllString(urlObj.Path, 1) != nil {
					_ = routes[index]
					break
				}
			}
		}
	}
}
<|endoftext|>