<commit_before>package retry

import "time"

// Retry retry N times
func Retry(trial uint, interval time.Duration, f func() error) (err error) {
	for trial > 0 {
		trial--
		err = f()
		if err == nil || trial <= 0 {
			break
		}
		time.Sleep(interval)
	}
	return err
}
<commit_msg>enhance documentation<commit_after>package retry

import "time"

// Retry calls the `fn` and if it returns the error, retry to call `fn` after `interval` duration.
// The `fn` is called up to `n` times.
func Retry(n uint, interval time.Duration, fn func() error) (err error) {
	for n > 0 {
		n--
		err = fn()
		if err == nil || n <= 0 {
			break
		}
		time.Sleep(interval)
	}
	return err
}
<|endoftext|>


<commit_before>package rcmgr

import (
	"fmt"
	"sync"

	"github.com/libp2p/go-buffer-pool"
	"github.com/libp2p/go-libp2p-core/network"
)

// Basic resource mamagement.
type Resources struct {
	limit    Limit
	nconns   int
	nstreams int
	memory   int64
	buffers  map[interface{}][]byte
}

// DAG ResourceScopes.
// Resources accounts for the node usage, constraints signify
// the dependencies that constrains resource usage.
type ResourceScope struct {
	mx   sync.Mutex
	rc   *Resources
	done bool

	constraints []*ResourceScope
}

var _ network.ResourceScope = (*ResourceScope)(nil)
var _ network.TransactionalScope = (*ResourceScope)(nil)

// Resources implementation
func (rc *Resources) checkMemory(rsvp int) error {
	// overflow check; this also has the side-effect that we cannot reserve negative memory.
	newmem := rc.memory + int64(rsvp)
	if newmem < rc.memory {
		return fmt.Errorf("memory reservation overflow: %w", ErrResourceLimitExceeded)
	}

	// limit check
	if newmem > rc.limit.GetMemoryLimit() {
		return fmt.Errorf("cannot reserve memory: %w", ErrResourceLimitExceeded)
	}

	return nil
}

func (rc *Resources) releaseBuffers() {
	for key, buf := range rc.buffers {
		pool.Put(buf)
		delete(rc.buffers, key)
	}
}

func (rc *Resources) reserveMemory(size int) error {
	if err := rc.checkMemory(size); err != nil {
		return err
	}

	rc.memory += int64(size)
	return nil
}

func (rc *Resources) releaseMemory(size int64) {
	rc.memory -= size

	// sanity check for bugs upstream
	if rc.memory < 0 {
		panic("BUG: too much memory released")
	}
}

func (rc *Resources) getBuffer(size int) ([]byte, error) {
	if err := rc.checkMemory(size); err != nil {
		return nil, err
	}

	buf := pool.Get(size)

	rc.memory += int64(size)
	rc.buffers[buf] = buf

	return buf, nil
}

func (rc *Resources) growBuffer(oldbuf []byte, newsize int) ([]byte, error) {
	grow := newsize - len(oldbuf)
	if err := rc.checkMemory(grow); err != nil {
		return nil, err
	}

	newbuf := pool.Get(newsize)
	copy(newbuf, oldbuf)

	rc.memory += int64(grow)
	rc.buffers[newbuf] = newbuf
	delete(rc.buffers, oldbuf)

	return newbuf, nil
}

func (rc *Resources) releaseBuffer(buf []byte) {
	rc.memory -= int64(len(buf))

	// sanity check for bugs upstream
	if rc.memory < 0 {
		panic("BUG: too much memory released")
	}

	delete(rc.buffers, buf)
	pool.Put(buf)
}

func (rc *Resources) addStream(count int) error {
	if rc.nstreams+count > rc.limit.GetStreamLimit() {
		return fmt.Errorf("cannot reserve stream: %w", ErrResourceLimitExceeded)
	}

	rc.nstreams += count
	return nil
}

func (rc *Resources) removeStream(count int) {
	rc.nstreams -= count

	if rc.nstreams < 0 {
		panic("BUG: too many streams released")
	}
}

func (rc *Resources) addConn(count int) error {
	if rc.nconns+count > rc.limit.GetConnLimit() {
		return fmt.Errorf("cannot reserve connection: %w", ErrResourceLimitExceeded)
	}

	rc.nconns += count
	return nil
}

func (rc *Resources) removeConn(count int) {
	rc.nconns -= count

	if rc.nconns < 0 {
		panic("BUG: too many connections released")
	}
}

func (rc *Resources) stat() network.ScopeStat {
	return network.ScopeStat{
		Memory:     rc.memory,
		NumConns:   rc.nconns,
		NumStreams: rc.nstreams,
	}
}

// ResourceScope implementation
func (s *ResourceScope) ReserveMemory(size int) error {
	s.mx.Lock()
	defer s.mx.Unlock()

	if s.done {
		return ErrResourceScopeClosed
	}

	if err := s.rc.reserveMemory(size); err != nil {
		return err
	}

	if err := s.reserveMemoryForConstraints(size); err != nil {
		s.rc.releaseMemory(int64(size))
		return err
	}

	return nil
}

func (s *ResourceScope) reserveMemoryForConstraints(size int) error {
	var reserved int
	var err error
	for _, cst := range s.constraints {
		if err = cst.ReserveMemoryForChild(size); err != nil {
			break
		}
		reserved++
	}

	if err != nil {
		// we failed because of a constraint; undo memory reservations
		for _, cst := range s.constraints[:reserved] {
			cst.ReleaseMemoryForChild(int64(size))
		}
	}

	return err
}

func (s *ResourceScope) ReserveMemoryForChild(size int) error {
	s.mx.Lock()
	defer s.mx.Unlock()

	if s.done {
		return ErrResourceScopeClosed
	}

	return s.rc.reserveMemory(size)
}

func (s *ResourceScope) ReleaseMemory(size int) {
	s.mx.Lock()
	defer s.mx.Unlock()

	if s.done {
		return
	}

	s.rc.releaseMemory(int64(size))
	for _, cst := range s.constraints {
		cst.ReleaseMemoryForChild(int64(size))
	}
}

func (s *ResourceScope) ReleaseMemoryForChild(size int64) {
	s.mx.Lock()
	defer s.mx.Unlock()

	if s.done {
		return
	}

	s.rc.releaseMemory(size)
}

func (s *ResourceScope) GetBuffer(size int) ([]byte, error) {
	s.mx.Lock()
	defer s.mx.Unlock()

	if s.done {
		return nil, ErrResourceScopeClosed
	}

	buf, err := s.rc.getBuffer(size)
	if err != nil {
		return nil, err
	}

	if err := s.reserveMemoryForConstraints(size); err != nil {
		s.rc.releaseBuffer(buf)
		return nil, err
	}

	return buf, err
}

func (s *ResourceScope) GrowBuffer(oldbuf []byte, newsize int) ([]byte, error) {
	s.mx.Lock()
	defer s.mx.Unlock()

	if s.done {
		return nil, ErrResourceScopeClosed
	}

	buf, err := s.rc.growBuffer(oldbuf, newsize)
	if err != nil {
		return nil, err
	}

	if err := s.reserveMemoryForConstraints(newsize - len(oldbuf)); err != nil {
		s.rc.releaseBuffer(buf)
		return nil, err
	}

	return buf, err
}

func (s *ResourceScope) ReleaseBuffer(buf []byte) {
	s.mx.Lock()
	defer s.mx.Unlock()

	if s.done {
		return
	}

	s.rc.releaseBuffer(buf)
	for _, cst := range s.constraints {
		cst.ReleaseMemoryForChild(int64(len(buf)))
	}
}

func (s *ResourceScope) AddStream(count int) error {
	s.mx.Lock()
	defer s.mx.Unlock()

	if s.done {
		return ErrResourceScopeClosed
	}

	if err := s.rc.addStream(count); err != nil {
		return err
	}

	var err error
	var reserved int
	for _, cst := range s.constraints {
		if err = cst.AddStreamForChild(count); err != nil {
			break
		}
		reserved++
	}

	if err != nil {
		for _, cst := range s.constraints[:reserved] {
			cst.RemoveStreamForChild(count)
		}
	}

	return err
}

func (s *ResourceScope) AddStreamForChild(count int) error {
	s.mx.Lock()
	defer s.mx.Unlock()

	return s.rc.addStream(count)
}

func (s *ResourceScope) RemoveStream(count int) {
	s.mx.Lock()
	defer s.mx.Unlock()

	s.rc.removeStream(count)
	for _, cst := range s.constraints {
		cst.RemoveStreamForChild(count)
	}
}

func (s *ResourceScope) RemoveStreamForChild(count int) {
	s.mx.Lock()
	defer s.mx.Unlock()
	s.rc.removeStream(count)
}

func (s *ResourceScope) AddConn(count int) error {
	s.mx.Lock()
	defer s.mx.Unlock()

	if s.done {
		return ErrResourceScopeClosed
	}

	if err := s.rc.addConn(count); err != nil {
		return err
	}

	var err error
	var reserved int
	for _, cst := range s.constraints {
		if err = cst.AddConnForChild(count); err != nil {
			break
		}
		reserved++
	}

	if err != nil {
		for _, cst := range s.constraints[:reserved] {
			cst.RemoveConnForChild(count)
		}
	}

	return err
}

func (s *ResourceScope) AddConnForChild(count int) error {
	s.mx.Lock()
	defer s.mx.Unlock()

	return s.rc.addConn(count)
}

func (s *ResourceScope) RemoveConn(count int) {
	s.mx.Lock()
	defer s.mx.Unlock()

	s.rc.removeConn(count)
	for _, cst := range s.constraints {
		cst.RemoveConnForChild(count)
	}
}

func (s *ResourceScope) RemoveConnForChild(count int) {
	s.mx.Lock()
	defer s.mx.Unlock()
	s.rc.removeConn(count)
}

func (s *ResourceScope) Done() {
	s.mx.Lock()
	defer s.mx.Unlock()

	if s.done {
		return
	}

	for _, cst := range s.constraints {
		cst.ReleaseMemoryForChild(s.rc.memory)
		cst.RemoveStreamForChild(s.rc.nstreams)
		cst.RemoveConnForChild(s.rc.nconns)
	}

	s.rc.releaseBuffers()

	s.rc.memory = 0
	s.rc.nstreams = 0
	s.rc.nconns = 0

	s.done = true
}

func (s *ResourceScope) Stat() network.ScopeStat {
	s.mx.Lock()
	defer s.mx.Unlock()

	return s.rc.stat()
}
<commit_msg>release buffer map at done<commit_after>package rcmgr

import (
	"fmt"
	"sync"

	"github.com/libp2p/go-buffer-pool"
	"github.com/libp2p/go-libp2p-core/network"
)

// Basic resource mamagement.
type Resources struct {
	limit    Limit
	nconns   int
	nstreams int
	memory   int64
	buffers  map[interface{}][]byte
}

// DAG ResourceScopes.
// Resources accounts for the node usage, constraints signify
// the dependencies that constrain resource usage.
type ResourceScope struct {
	mx   sync.Mutex
	rc   *Resources
	done bool

	constraints []*ResourceScope
}

var _ network.ResourceScope = (*ResourceScope)(nil)
var _ network.TransactionalScope = (*ResourceScope)(nil)

// Resources implementation
func (rc *Resources) checkMemory(rsvp int) error {
	// overflow check; this also has the side-effect that we cannot reserve negative memory.
	newmem := rc.memory + int64(rsvp)
	if newmem < rc.memory {
		return fmt.Errorf("memory reservation overflow: %w", ErrResourceLimitExceeded)
	}

	// limit check
	if newmem > rc.limit.GetMemoryLimit() {
		return fmt.Errorf("cannot reserve memory: %w", ErrResourceLimitExceeded)
	}

	return nil
}

func (rc *Resources) releaseBuffers() {
	for key, buf := range rc.buffers {
		pool.Put(buf)
		delete(rc.buffers, key)
	}
}

func (rc *Resources) reserveMemory(size int) error {
	if err := rc.checkMemory(size); err != nil {
		return err
	}

	rc.memory += int64(size)
	return nil
}

func (rc *Resources) releaseMemory(size int64) {
	rc.memory -= size

	// sanity check for bugs upstream
	if rc.memory < 0 {
		panic("BUG: too much memory released")
	}
}

func (rc *Resources) getBuffer(size int) ([]byte, error) {
	if err := rc.checkMemory(size); err != nil {
		return nil, err
	}

	buf := pool.Get(size)

	rc.memory += int64(size)
	rc.buffers[buf] = buf

	return buf, nil
}

func (rc *Resources) growBuffer(oldbuf []byte, newsize int) ([]byte, error) {
	grow := newsize - len(oldbuf)
	if err := rc.checkMemory(grow); err != nil {
		return nil, err
	}

	newbuf := pool.Get(newsize)
	copy(newbuf, oldbuf)

	rc.memory += int64(grow)
	rc.buffers[newbuf] = newbuf
	delete(rc.buffers, oldbuf)

	return newbuf, nil
}

func (rc *Resources) releaseBuffer(buf []byte) {
	rc.memory -= int64(len(buf))

	// sanity check for bugs upstream
	if rc.memory < 0 {
		panic("BUG: too much memory released")
	}

	delete(rc.buffers, buf)
	pool.Put(buf)
}

func (rc *Resources) addStream(count int) error {
	if rc.nstreams+count > rc.limit.GetStreamLimit() {
		return fmt.Errorf("cannot reserve stream: %w", ErrResourceLimitExceeded)
	}

	rc.nstreams += count
	return nil
}

func (rc *Resources) removeStream(count int) {
	rc.nstreams -= count

	if rc.nstreams < 0 {
		panic("BUG: too many streams released")
	}
}

func (rc *Resources) addConn(count int) error {
	if rc.nconns+count > rc.limit.GetConnLimit() {
		return fmt.Errorf("cannot reserve connection: %w", ErrResourceLimitExceeded)
	}

	rc.nconns += count
	return nil
}

func (rc *Resources) removeConn(count int) {
	rc.nconns -= count

	if rc.nconns < 0 {
		panic("BUG: too many connections released")
	}
}

func (rc *Resources) stat() network.ScopeStat {
	return network.ScopeStat{
		Memory:     rc.memory,
		NumConns:   rc.nconns,
		NumStreams: rc.nstreams,
	}
}

// ResourceScope implementation
func (s *ResourceScope) ReserveMemory(size int) error {
	s.mx.Lock()
	defer s.mx.Unlock()

	if s.done {
		return ErrResourceScopeClosed
	}

	if err := s.rc.reserveMemory(size); err != nil {
		return err
	}

	if err := s.reserveMemoryForConstraints(size); err != nil {
		s.rc.releaseMemory(int64(size))
		return err
	}

	return nil
}

func (s *ResourceScope) reserveMemoryForConstraints(size int) error {
	var reserved int
	var err error
	for _, cst := range s.constraints {
		if err = cst.ReserveMemoryForChild(size); err != nil {
			break
		}
		reserved++
	}

	if err != nil {
		// we failed because of a constraint; undo memory reservations
		for _, cst := range s.constraints[:reserved] {
			cst.ReleaseMemoryForChild(int64(size))
		}
	}

	return err
}

func (s *ResourceScope) ReserveMemoryForChild(size int) error {
	s.mx.Lock()
	defer s.mx.Unlock()

	if s.done {
		return ErrResourceScopeClosed
	}

	return s.rc.reserveMemory(size)
}

func (s *ResourceScope) ReleaseMemory(size int) {
	s.mx.Lock()
	defer s.mx.Unlock()

	if s.done {
		return
	}

	s.rc.releaseMemory(int64(size))
	for _, cst := range s.constraints {
		cst.ReleaseMemoryForChild(int64(size))
	}
}

func (s *ResourceScope) ReleaseMemoryForChild(size int64) {
	s.mx.Lock()
	defer s.mx.Unlock()

	if s.done {
		return
	}

	s.rc.releaseMemory(size)
}

func (s *ResourceScope) GetBuffer(size int) ([]byte, error) {
	s.mx.Lock()
	defer s.mx.Unlock()

	if s.done {
		return nil, ErrResourceScopeClosed
	}

	buf, err := s.rc.getBuffer(size)
	if err != nil {
		return nil, err
	}

	if err := s.reserveMemoryForConstraints(size); err != nil {
		s.rc.releaseBuffer(buf)
		return nil, err
	}

	return buf, err
}

func (s *ResourceScope) GrowBuffer(oldbuf []byte, newsize int) ([]byte, error) {
	s.mx.Lock()
	defer s.mx.Unlock()

	if s.done {
		return nil, ErrResourceScopeClosed
	}

	buf, err := s.rc.growBuffer(oldbuf, newsize)
	if err != nil {
		return nil, err
	}

	if err := s.reserveMemoryForConstraints(newsize - len(oldbuf)); err != nil {
		s.rc.releaseBuffer(buf)
		return nil, err
	}

	return buf, err
}

func (s *ResourceScope) ReleaseBuffer(buf []byte) {
	s.mx.Lock()
	defer s.mx.Unlock()

	if s.done {
		return
	}

	s.rc.releaseBuffer(buf)
	for _, cst := range s.constraints {
		cst.ReleaseMemoryForChild(int64(len(buf)))
	}
}

func (s *ResourceScope) AddStream(count int) error {
	s.mx.Lock()
	defer s.mx.Unlock()

	if s.done {
		return ErrResourceScopeClosed
	}

	if err := s.rc.addStream(count); err != nil {
		return err
	}

	var err error
	var reserved int
	for _, cst := range s.constraints {
		if err = cst.AddStreamForChild(count); err != nil {
			break
		}
		reserved++
	}

	if err != nil {
		for _, cst := range s.constraints[:reserved] {
			cst.RemoveStreamForChild(count)
		}
	}

	return err
}

func (s *ResourceScope) AddStreamForChild(count int) error {
	s.mx.Lock()
	defer s.mx.Unlock()

	return s.rc.addStream(count)
}

func (s *ResourceScope) RemoveStream(count int) {
	s.mx.Lock()
	defer s.mx.Unlock()

	s.rc.removeStream(count)
	for _, cst := range s.constraints {
		cst.RemoveStreamForChild(count)
	}
}

func (s *ResourceScope) RemoveStreamForChild(count int) {
	s.mx.Lock()
	defer s.mx.Unlock()
	s.rc.removeStream(count)
}

func (s *ResourceScope) AddConn(count int) error {
	s.mx.Lock()
	defer s.mx.Unlock()

	if s.done {
		return ErrResourceScopeClosed
	}

	if err := s.rc.addConn(count); err != nil {
		return err
	}

	var err error
	var reserved int
	for _, cst := range s.constraints {
		if err = cst.AddConnForChild(count); err != nil {
			break
		}
		reserved++
	}

	if err != nil {
		for _, cst := range s.constraints[:reserved] {
			cst.RemoveConnForChild(count)
		}
	}

	return err
}

func (s *ResourceScope) AddConnForChild(count int) error {
	s.mx.Lock()
	defer s.mx.Unlock()

	return s.rc.addConn(count)
}

func (s *ResourceScope) RemoveConn(count int) {
	s.mx.Lock()
	defer s.mx.Unlock()

	s.rc.removeConn(count)
	for _, cst := range s.constraints {
		cst.RemoveConnForChild(count)
	}
}

func (s *ResourceScope) RemoveConnForChild(count int) {
	s.mx.Lock()
	defer s.mx.Unlock()
	s.rc.removeConn(count)
}

func (s *ResourceScope) Done() {
	s.mx.Lock()
	defer s.mx.Unlock()

	if s.done {
		return
	}

	for _, cst := range s.constraints {
		cst.ReleaseMemoryForChild(s.rc.memory)
		cst.RemoveStreamForChild(s.rc.nstreams)
		cst.RemoveConnForChild(s.rc.nconns)
	}

	s.rc.releaseBuffers()

	s.rc.nstreams = 0
	s.rc.nconns = 0
	s.rc.memory = 0
	s.rc.buffers = nil

	s.done = true
}

func (s *ResourceScope) Stat() network.ScopeStat {
	s.mx.Lock()
	defer s.mx.Unlock()

	return s.rc.stat()
}
<|endoftext|>


<commit_before>package ruler

import (
	"encoding/json"
	"github.com/tj/go-debug"
	"reflect"
	"regexp"
	"strings"
)

var ruleDebug = debug.Debug("ruler:rule")

// we'll use these values
// to avoid passing strings to our
// special comparison func for these comparators
const (
	eq        = iota
	neq       = iota
	gt        = iota
	gte       = iota
	lt        = iota
	lte       = iota
	exists    = iota
	nexists   = iota
	regex     = iota
	matches   = iota
	contains  = iota
	ncontains = iota
)

type Ruler struct {
	rules []*Rule
}

// creates a new Ruler for you
// optionally accepts a pointer to a slice of filters
// if you have filters that you want to start with
func NewRuler(rules *[]*Rule) *Ruler {
	if rules != nil {
		return &Ruler{
			*rules,
		}
	}

	return &Ruler{}
}

// returns a new ruler with filters parsed from JSON data
// expects JSON as a slice of bytes and will parse your JSON for you!
func NewRulerWithJson(jsonstr []byte) (*Ruler, error) {
	var rules *[]*Rule

	err := json.Unmarshal(jsonstr, &rules)
	if err != nil {
		return nil, err
	}

	return NewRuler(rules), nil
}

// adds a new rule for the property at `path`
// returns a RulerFilter that you can use to add conditions
// and more filters
func (r *Ruler) Rule(path string) *RulerRule {
	rule := &Rule{
		"",
		path,
		nil,
	}

	return &RulerRule{
		r,
		rule,
	}
}

// tests all the rules (i.e. filters) in your set of rules,
// given a map that looks like a JSON object
// (map[string]interface{})
func (r *Ruler) Test(o map[string]interface{}) bool {
	for _, f := range r.rules {
		val := pluck(o, f.Path)

		if val != nil {
			// both the actual and expected value must be comparable
			a := reflect.TypeOf(val)
			e := reflect.TypeOf(f.Value)

			if !a.Comparable() || !e.Comparable() {
				return false
			}

			if !r.compare(f, val) {
				return false
			}
		} else if val == nil && (f.Comparator == "exists" || f.Comparator == "nexists") {
			// either one of these can be done
			return r.compare(f, val)
		} else {
			ruleDebug("did not find property (%s) on map", f.Path)
			// if we couldn't find the value on the map
			// and the comparator isn't exists/nexists, this fails
			return false
		}

	}

	return true
}

// compares real v. actual values
func (r *Ruler) compare(f *Rule, actual interface{}) bool {
	ruleDebug("beginning comparison")
	expected := f.Value
	switch f.Comparator {
	case "eq":
		return actual == expected

	case "neq":
		return actual != expected

	case "gt":
		return r.inequality(gt, actual, expected)

	case "gte":
		return r.inequality(gte, actual, expected)

	case "lt":
		return r.inequality(lt, actual, expected)

	case "lte":
		return r.inequality(lte, actual, expected)

	case "exists":
		// not sure this makes complete sense
		return actual != nil

	case "nexists":
		return actual == nil

	case "regex":
		fallthrough
	case "contains":
		fallthrough
	case "matches":
		return r.regexp(actual, expected)

	case "ncontains":
		return !r.regexp(actual, expected)
	default:
		//should probably return an error or something
		//but this is good for now
		//if comparator is not implemented, return false
		return false
	}
}

// runs equality comparison
// separated in a different function because
// we need to do another type assertion here
// and some other acrobatics
func (r *Ruler) inequality(op int, actual, expected interface{}) bool {
	// need some variables for these deals
	ruleDebug("entered inequality comparison")
	var cmpStr [2]string
	var cmpUint [2]uint64
	var cmpInt [2]int64
	var cmpFloat [2]float64

	for idx, i := range []interface{}{actual, expected} {
		switch t := i.(type) {
		case uint8:
			cmpUint[idx] = uint64(t)
		case uint16:
			cmpUint[idx] = uint64(t)
		case uint32:
			cmpUint[idx] = uint64(t)
		case uint64:
			cmpUint[idx] = t
		case uint:
			cmpUint[idx] = uint64(t)
		case int8:
			cmpInt[idx] = int64(t)
		case int16:
			cmpInt[idx] = int64(t)
		case int32:
			cmpInt[idx] = int64(t)
		case int64:
			cmpInt[idx] = t
		case int:
			cmpInt[idx] = int64(t)
		case float32:
			cmpFloat[idx] = float64(t)
		case float64:
			cmpFloat[idx] = t
		case string:
			cmpStr[idx] = t
		default:
			ruleDebug("invalid type for inequality comparison")
			return false
		}
	}

	// whichever of these works, we're happy with
	// but if you're trying to compare a string to an int, oh well!
	switch op {
	case gt:
		return cmpStr[0] > cmpStr[1] ||
			cmpUint[0] > cmpUint[1] ||
			cmpInt[0] > cmpInt[1] ||
			cmpFloat[0] > cmpFloat[1]
	case gte:
		return cmpStr[0] >= cmpStr[1] ||
			cmpUint[0] >= cmpUint[1] ||
			cmpInt[0] >= cmpInt[1] ||
			cmpFloat[0] >= cmpFloat[1]
	case lt:
		return cmpStr[0] < cmpStr[1] ||
			cmpUint[0] < cmpUint[1] ||
			cmpInt[0] < cmpInt[1] ||
			cmpFloat[0] < cmpFloat[1]
	case lte:
		return cmpStr[0] <= cmpStr[1] ||
			cmpUint[0] <= cmpUint[1] ||
			cmpInt[0] <= cmpInt[1] ||
			cmpFloat[0] <= cmpFloat[1]
	}

	return false
}

func (r *Ruler) regexp(actual, expected interface{}) bool {
	ruleDebug("beginning regexp")
	// regexps must be strings
	var streg string
	var ok bool
	if streg, ok = expected.(string); !ok {
		ruleDebug("expected value not actually a string, bailing")
		return false
	}

	var astring string
	if astring, ok = actual.(string); !ok {
		ruleDebug("actual value not actually a string, bailing")
		return false
	}

	reg, err := regexp.Compile(streg)
	if err != nil {
		ruleDebug("regexp is bad, bailing")
		return false
	}

	return reg.MatchString(astring)
}

// given a map, pull a property from it at some deeply nested depth
// this reimplements (most of) JS `pluck` in go: https://github.com/gjohnson/pluck
func pluck(o map[string]interface{}, path string) interface{} {
	// support dots for now ebcause thats all we need
	parts := strings.Split(path, ".")

	if len(parts) == 1 && o[parts[0]] != nil {
		// if there is only one part, just return that property value
		return o[parts[0]]
	} else if len(parts) > 1 && o[parts[0]] != nil {
		var prev map[string]interface{}
		var ok bool
		if prev, ok = o[parts[0]].(map[string]interface{}); !ok {
			// not an object type! ...or a map, yeah, that.
			return nil
		}

		for i := 1; i < len(parts)-1; i += 1 {
			// we need to check the existence of another
			// map[string]interface for every property along the way
			cp := parts[i]

			if prev[cp] == nil {
				// didn't find the property, it's missing
				return nil
			}
			var ok bool
			if prev, ok = prev[cp].(map[string]interface{}); !ok {
				return nil
			}
		}

		if prev[parts[len(parts)-1]] != nil {
			return prev[parts[len(parts)-1]]
		} else {
			return nil
		}
	}

	return nil
}
<commit_msg>add rule to rules slice (oops)<commit_after>package ruler

import (
	"encoding/json"
	"github.com/tj/go-debug"
	"reflect"
	"regexp"
	"strings"
)

var ruleDebug = debug.Debug("ruler:rule")

// we'll use these values
// to avoid passing strings to our
// special comparison func for these comparators
const (
	eq        = iota
	neq       = iota
	gt        = iota
	gte       = iota
	lt        = iota
	lte       = iota
	exists    = iota
	nexists   = iota
	regex     = iota
	matches   = iota
	contains  = iota
	ncontains = iota
)

type Ruler struct {
	rules []*Rule
}

// creates a new Ruler for you
// optionally accepts a pointer to a slice of filters
// if you have filters that you want to start with
func NewRuler(rules *[]*Rule) *Ruler {
	if rules != nil {
		return &Ruler{
			*rules,
		}
	}

	return &Ruler{}
}

// returns a new ruler with filters parsed from JSON data
// expects JSON as a slice of bytes and will parse your JSON for you!
func NewRulerWithJson(jsonstr []byte) (*Ruler, error) {
	var rules *[]*Rule

	err := json.Unmarshal(jsonstr, &rules)
	if err != nil {
		return nil, err
	}

	return NewRuler(rules), nil
}

// adds a new rule for the property at `path`
// returns a RulerFilter that you can use to add conditions
// and more filters
func (r *Ruler) Rule(path string) *RulerRule {
	rule := &Rule{
		"",
		path,
		nil,
	}

	r.rules = append(r.rules, rule)

	return &RulerRule{
		r,
		rule,
	}
}

// tests all the rules (i.e. filters) in your set of rules,
// given a map that looks like a JSON object
// (map[string]interface{})
func (r *Ruler) Test(o map[string]interface{}) bool {
	for _, f := range r.rules {
		val := pluck(o, f.Path)

		if val != nil {
			// both the actual and expected value must be comparable
			a := reflect.TypeOf(val)
			e := reflect.TypeOf(f.Value)

			if !a.Comparable() || !e.Comparable() {
				return false
			}

			if !r.compare(f, val) {
				return false
			}
		} else if val == nil && (f.Comparator == "exists" || f.Comparator == "nexists") {
			// either one of these can be done
			return r.compare(f, val)
		} else {
			ruleDebug("did not find property (%s) on map", f.Path)
			// if we couldn't find the value on the map
			// and the comparator isn't exists/nexists, this fails
			return false
		}

	}

	return true
}

// compares real v. actual values
func (r *Ruler) compare(f *Rule, actual interface{}) bool {
	ruleDebug("beginning comparison")
	expected := f.Value
	switch f.Comparator {
	case "eq":
		return actual == expected

	case "neq":
		return actual != expected

	case "gt":
		return r.inequality(gt, actual, expected)

	case "gte":
		return r.inequality(gte, actual, expected)

	case "lt":
		return r.inequality(lt, actual, expected)

	case "lte":
		return r.inequality(lte, actual, expected)

	case "exists":
		// not sure this makes complete sense
		return actual != nil

	case "nexists":
		return actual == nil

	case "regex":
		fallthrough
	case "contains":
		fallthrough
	case "matches":
		return r.regexp(actual, expected)

	case "ncontains":
		return !r.regexp(actual, expected)
	default:
		//should probably return an error or something
		//but this is good for now
		//if comparator is not implemented, return false
		return false
	}
}

// runs equality comparison
// separated in a different function because
// we need to do another type assertion here
// and some other acrobatics
func (r *Ruler) inequality(op int, actual, expected interface{}) bool {
	// need some variables for these deals
	ruleDebug("entered inequality comparison")
	var cmpStr [2]string
	var cmpUint [2]uint64
	var cmpInt [2]int64
	var cmpFloat [2]float64

	for idx, i := range []interface{}{actual, expected} {
		switch t := i.(type) {
		case uint8:
			cmpUint[idx] = uint64(t)
		case uint16:
			cmpUint[idx] = uint64(t)
		case uint32:
			cmpUint[idx] = uint64(t)
		case uint64:
			cmpUint[idx] = t
		case uint:
			cmpUint[idx] = uint64(t)
		case int8:
			cmpInt[idx] = int64(t)
		case int16:
			cmpInt[idx] = int64(t)
		case int32:
			cmpInt[idx] = int64(t)
		case int64:
			cmpInt[idx] = t
		case int:
			cmpInt[idx] = int64(t)
		case float32:
			cmpFloat[idx] = float64(t)
		case float64:
			cmpFloat[idx] = t
		case string:
			cmpStr[idx] = t
		default:
			ruleDebug("invalid type for inequality comparison")
			return false
		}
	}

	// whichever of these works, we're happy with
	// but if you're trying to compare a string to an int, oh well!
	switch op {
	case gt:
		return cmpStr[0] > cmpStr[1] ||
			cmpUint[0] > cmpUint[1] ||
			cmpInt[0] > cmpInt[1] ||
			cmpFloat[0] > cmpFloat[1]
	case gte:
		return cmpStr[0] >= cmpStr[1] ||
			cmpUint[0] >= cmpUint[1] ||
			cmpInt[0] >= cmpInt[1] ||
			cmpFloat[0] >= cmpFloat[1]
	case lt:
		return cmpStr[0] < cmpStr[1] ||
			cmpUint[0] < cmpUint[1] ||
			cmpInt[0] < cmpInt[1] ||
			cmpFloat[0] < cmpFloat[1]
	case lte:
		return cmpStr[0] <= cmpStr[1] ||
			cmpUint[0] <= cmpUint[1] ||
			cmpInt[0] <= cmpInt[1] ||
			cmpFloat[0] <= cmpFloat[1]
	}

	return false
}

func (r *Ruler) regexp(actual, expected interface{}) bool {
	ruleDebug("beginning regexp")
	// regexps must be strings
	var streg string
	var ok bool
	if streg, ok = expected.(string); !ok {
		ruleDebug("expected value not actually a string, bailing")
		return false
	}

	var astring string
	if astring, ok = actual.(string); !ok {
		ruleDebug("actual value not actually a string, bailing")
		return false
	}

	reg, err := regexp.Compile(streg)
	if err != nil {
		ruleDebug("regexp is bad, bailing")
		return false
	}

	return reg.MatchString(astring)
}

// given a map, pull a property from it at some deeply nested depth
// this reimplements (most of) JS `pluck` in go: https://github.com/gjohnson/pluck
func pluck(o map[string]interface{}, path string) interface{} {
	// support dots for now ebcause thats all we need
	parts := strings.Split(path, ".")

	if len(parts) == 1 && o[parts[0]] != nil {
		// if there is only one part, just return that property value
		return o[parts[0]]
	} else if len(parts) > 1 && o[parts[0]] != nil {
		var prev map[string]interface{}
		var ok bool
		if prev, ok = o[parts[0]].(map[string]interface{}); !ok {
			// not an object type! ...or a map, yeah, that.
			return nil
		}

		for i := 1; i < len(parts)-1; i += 1 {
			// we need to check the existence of another
			// map[string]interface for every property along the way
			cp := parts[i]

			if prev[cp] == nil {
				// didn't find the property, it's missing
				return nil
			}
			var ok bool
			if prev, ok = prev[cp].(map[string]interface{}); !ok {
				return nil
			}
		}

		if prev[parts[len(parts)-1]] != nil {
			return prev[parts[len(parts)-1]]
		} else {
			return nil
		}
	}

	return nil
}
<|endoftext|>


<commit_before>// Copyright © 2015-2019 Hilko Bengen <bengen@hilluzination.de>
// All rights reserved.
//
// Use of this source code is governed by the license that can be
// found in the LICENSE file.

// Package yara provides bindings to the YARA library.
package yara

/*
#include <yara.h>

int scanCallbackFunc(int, void*, void*);
*/
import "C"
import (
	"errors"
	"runtime"
	"time"
	"unsafe"
)

// Rules contains a compiled YARA ruleset.
type Rules struct {
	*rules
}

type rules struct {
	cptr *C.YR_RULES
}

var dummy *[]MatchRule

// A MatchRule represents a rule successfully matched against a block
// of data.
type MatchRule struct {
	Rule      string
	Namespace string
	Tags      []string
	Meta      map[string]interface{}
	Strings   []MatchString
}

// A MatchString represents a string declared and matched in a rule. Name is
// the string's identifier. Offset is the offset within the file where the match
// was found. Data contains the portion of the file that matches, but it will be
// truncated to the amount specified with SetMaxMatchData, which by default is
// 512 bytes (this default value is controlled by the DEFAULT_MAX_MATCH_DATA
// macro defined in libyara.h). Length is the actual length of the match, and
// can be higher than len(Data).
type MatchString struct {
	Name   string
	Offset uint64
	Data   []byte
	Length uint64
}

// ScanMem scans an in-memory buffer using the ruleset, returning
// matches via a list of MatchRule objects.
func (r *Rules) ScanMem(buf []byte, flags ScanFlags, timeout time.Duration) (matches []MatchRule, err error) {
	cb := MatchRules{}
	err = r.ScanMemWithCallback(buf, flags, timeout, &cb)
	matches = cb
	return
}

// ScanMemWithCallback scans an in-memory buffer using the ruleset.
// For every event emitted by libyara, the appropriate method on the
// ScanCallback object is called.
func (r *Rules) ScanMemWithCallback(buf []byte, flags ScanFlags, timeout time.Duration, cb ScanCallback) (err error) {
	var ptr *C.uint8_t
	if len(buf) > 0 {
		ptr = (*C.uint8_t)(unsafe.Pointer(&(buf[0])))
	}
	cbc := &scanCallbackContainer{ScanCallback: cb}
	defer cbc.destroy()
	id := callbackData.Put(cbc)
	defer callbackData.Delete(id)
	err = newError(C.yr_rules_scan_mem(
		r.cptr,
		ptr,
		C.size_t(len(buf)),
		C.int(flags),
		C.YR_CALLBACK_FUNC(C.scanCallbackFunc),
		id,
		C.int(timeout/time.Second)))
	keepAlive(r)
	return
}

// ScanFile scans a file using the ruleset, returning matches via a
// list of MatchRule objects.
func (r *Rules) ScanFile(filename string, flags ScanFlags, timeout time.Duration) (matches []MatchRule, err error) {
	cb := MatchRules{}
	err = r.ScanFileWithCallback(filename, flags, timeout, &cb)
	matches = cb
	return
}

// ScanFileWithCallback scans a file using the ruleset. For every
// event emitted by libyara, the appropriate method on the
// ScanCallback object is called.
func (r *Rules) ScanFileWithCallback(filename string, flags ScanFlags, timeout time.Duration, cb ScanCallback) (err error) {
	cfilename := C.CString(filename)
	defer C.free(unsafe.Pointer(cfilename))
	cbc := &scanCallbackContainer{ScanCallback: cb}
	defer cbc.destroy()
	id := callbackData.Put(cbc)
	defer callbackData.Delete(id)
	err = newError(C.yr_rules_scan_file(
		r.cptr,
		cfilename,
		C.int(flags),
		C.YR_CALLBACK_FUNC(C.scanCallbackFunc),
		id,
		C.int(timeout/time.Second)))
	keepAlive(r)
	return
}

// ScanProc scans a live process using the ruleset, returning matches
// via a list of MatchRule objects.
func (r *Rules) ScanProc(pid int, flags ScanFlags, timeout time.Duration) (matches []MatchRule, err error) {
	cb := MatchRules{}
	err = r.ScanProcWithCallback(pid, flags, timeout, &cb)
	matches = cb
	return
}

// ScanProcWithCallback scans a live process using the ruleset.  For
// every event emitted by libyara, the appropriate method on the
// ScanCallback object is called.
func (r *Rules) ScanProcWithCallback(pid int, flags ScanFlags, timeout time.Duration, cb ScanCallback) (err error) {
	cbc := &scanCallbackContainer{ScanCallback: cb}
	defer cbc.destroy()
	id := callbackData.Put(cbc)
	defer callbackData.Delete(id)
	err = newError(C.yr_rules_scan_proc(
		r.cptr,
		C.int(pid),
		C.int(flags),
		C.YR_CALLBACK_FUNC(C.scanCallbackFunc),
		id,
		C.int(timeout/time.Second)))
	keepAlive(r)
	return
}

// Save writes a compiled ruleset to filename.
func (r *Rules) Save(filename string) (err error) {
	cfilename := C.CString(filename)
	defer C.free(unsafe.Pointer(cfilename))
	err = newError(C.yr_rules_save(r.cptr, cfilename))
	keepAlive(r)
	return
}

// LoadRules retrieves a compiled ruleset from filename.
func LoadRules(filename string) (*Rules, error) {
	r := &Rules{rules: &rules{}}
	cfilename := C.CString(filename)
	defer C.free(unsafe.Pointer(cfilename))
	if err := newError(C.yr_rules_load(cfilename,
		&(r.rules.cptr))); err != nil {
		return nil, err
	}
	runtime.SetFinalizer(r.rules, (*rules).finalize)
	return r, nil
}

func (r *rules) finalize() {
	C.yr_rules_destroy(r.cptr)
	runtime.SetFinalizer(r, nil)
}

// Destroy destroys the YARA data structure representing a ruleset.
// Since a Finalizer for the underlying YR_RULES structure is
// automatically set up on creation, it should not be necessary to
// explicitly call this method.
func (r *Rules) Destroy() {
	if r.rules != nil {
		r.rules.finalize()
		r.rules = nil
	}
}

// DefineVariable defines a named variable for use by the compiler.
// Boolean, int64, float64, and string types are supported.
func (r *Rules) DefineVariable(identifier string, value interface{}) (err error) {
	cid := C.CString(identifier)
	defer C.free(unsafe.Pointer(cid))
	switch value.(type) {
	case bool:
		var v int
		if value.(bool) {
			v = 1
		}
		err = newError(C.yr_rules_define_boolean_variable(
			r.cptr, cid, C.int(v)))
	case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
		value := toint64(value)
		err = newError(C.yr_rules_define_integer_variable(
			r.cptr, cid, C.int64_t(value)))
	case float64:
		err = newError(C.yr_rules_define_float_variable(
			r.cptr, cid, C.double(value.(float64))))
	case string:
		cvalue := C.CString(value.(string))
		defer C.free(unsafe.Pointer(cvalue))
		err = newError(C.yr_rules_define_string_variable(
			r.cptr, cid, cvalue))
	default:
		err = errors.New("wrong value type passed to DefineVariable; bool, int64, float64, string are accepted")
	}
	keepAlive(r)
	return
}

// GetRules returns a slice of rule objects that are part of the
// ruleset
func (r *Rules) GetRules() (rv []Rule) {
	for p := unsafe.Pointer(r.cptr.rules_table); (*C.YR_RULE)(p).flags&C.RULE_FLAGS_NULL == 0; p = unsafe.Pointer(uintptr(p) + unsafe.Sizeof(*r.cptr.rules_table)) {
		rv = append(rv, Rule{(*C.YR_RULE)(p)})
	}
	return
}
<commit_msg>Use yr_rules_foreach macro for (*Rules) GetRules.<commit_after>// Copyright © 2015-2019 Hilko Bengen <bengen@hilluzination.de>
// All rights reserved.
//
// Use of this source code is governed by the license that can be
// found in the LICENSE file.

// Package yara provides bindings to the YARA library.
package yara

/*
#include <yara.h>

int scanCallbackFunc(int, void*, void*);

// get_rules returns pointers to the RULE objects for a ruleset, using
// YARA's macro-based implementation.
static void get_rules(YR_RULES *ruleset, const YR_RULE *rules[], int *n) {
	const YR_RULE *rule;
	int i = 0;
	yr_rules_foreach(ruleset, rule) {
		if (i < *n)
			rules[i] = rule;
		i++;
	}
	*n = i;
	return;
}
*/
import "C"
import (
	"errors"
	"runtime"
	"time"
	"unsafe"
)

// Rules contains a compiled YARA ruleset.
type Rules struct {
	*rules
}

type rules struct {
	cptr *C.YR_RULES
}

var dummy *[]MatchRule

// A MatchRule represents a rule successfully matched against a block
// of data.
type MatchRule struct {
	Rule      string
	Namespace string
	Tags      []string
	Meta      map[string]interface{}
	Strings   []MatchString
}

// A MatchString represents a string declared and matched in a rule. Name is
// the string's identifier. Offset is the offset within the file where the match
// was found. Data contains the portion of the file that matches, but it will be
// truncated to the amount specified with SetMaxMatchData, which by default is
// 512 bytes (this default value is controlled by the DEFAULT_MAX_MATCH_DATA
// macro defined in libyara.h). Length is the actual length of the match, and
// can be higher than len(Data).
type MatchString struct {
	Name   string
	Offset uint64
	Data   []byte
	Length uint64
}

// ScanMem scans an in-memory buffer using the ruleset, returning
// matches via a list of MatchRule objects.
func (r *Rules) ScanMem(buf []byte, flags ScanFlags, timeout time.Duration) (matches []MatchRule, err error) {
	cb := MatchRules{}
	err = r.ScanMemWithCallback(buf, flags, timeout, &cb)
	matches = cb
	return
}

// ScanMemWithCallback scans an in-memory buffer using the ruleset.
// For every event emitted by libyara, the appropriate method on the
// ScanCallback object is called.
func (r *Rules) ScanMemWithCallback(buf []byte, flags ScanFlags, timeout time.Duration, cb ScanCallback) (err error) {
	var ptr *C.uint8_t
	if len(buf) > 0 {
		ptr = (*C.uint8_t)(unsafe.Pointer(&(buf[0])))
	}
	cbc := &scanCallbackContainer{ScanCallback: cb}
	defer cbc.destroy()
	id := callbackData.Put(cbc)
	defer callbackData.Delete(id)
	err = newError(C.yr_rules_scan_mem(
		r.cptr,
		ptr,
		C.size_t(len(buf)),
		C.int(flags),
		C.YR_CALLBACK_FUNC(C.scanCallbackFunc),
		id,
		C.int(timeout/time.Second)))
	keepAlive(r)
	return
}

// ScanFile scans a file using the ruleset, returning matches via a
// list of MatchRule objects.
func (r *Rules) ScanFile(filename string, flags ScanFlags, timeout time.Duration) (matches []MatchRule, err error) {
	cb := MatchRules{}
	err = r.ScanFileWithCallback(filename, flags, timeout, &cb)
	matches = cb
	return
}

// ScanFileWithCallback scans a file using the ruleset. For every
// event emitted by libyara, the appropriate method on the
// ScanCallback object is called.
func (r *Rules) ScanFileWithCallback(filename string, flags ScanFlags, timeout time.Duration, cb ScanCallback) (err error) {
	cfilename := C.CString(filename)
	defer C.free(unsafe.Pointer(cfilename))
	cbc := &scanCallbackContainer{ScanCallback: cb}
	defer cbc.destroy()
	id := callbackData.Put(cbc)
	defer callbackData.Delete(id)
	err = newError(C.yr_rules_scan_file(
		r.cptr,
		cfilename,
		C.int(flags),
		C.YR_CALLBACK_FUNC(C.scanCallbackFunc),
		id,
		C.int(timeout/time.Second)))
	keepAlive(r)
	return
}

// ScanProc scans a live process using the ruleset, returning matches
// via a list of MatchRule objects.
func (r *Rules) ScanProc(pid int, flags ScanFlags, timeout time.Duration) (matches []MatchRule, err error) {
	cb := MatchRules{}
	err = r.ScanProcWithCallback(pid, flags, timeout, &cb)
	matches = cb
	return
}

// ScanProcWithCallback scans a live process using the ruleset.  For
// every event emitted by libyara, the appropriate method on the
// ScanCallback object is called.
func (r *Rules) ScanProcWithCallback(pid int, flags ScanFlags, timeout time.Duration, cb ScanCallback) (err error) {
	cbc := &scanCallbackContainer{ScanCallback: cb}
	defer cbc.destroy()
	id := callbackData.Put(cbc)
	defer callbackData.Delete(id)
	err = newError(C.yr_rules_scan_proc(
		r.cptr,
		C.int(pid),
		C.int(flags),
		C.YR_CALLBACK_FUNC(C.scanCallbackFunc),
		id,
		C.int(timeout/time.Second)))
	keepAlive(r)
	return
}

// Save writes a compiled ruleset to filename.
func (r *Rules) Save(filename string) (err error) {
	cfilename := C.CString(filename)
	defer C.free(unsafe.Pointer(cfilename))
	err = newError(C.yr_rules_save(r.cptr, cfilename))
	keepAlive(r)
	return
}

// LoadRules retrieves a compiled ruleset from filename.
func LoadRules(filename string) (*Rules, error) {
	r := &Rules{rules: &rules{}}
	cfilename := C.CString(filename)
	defer C.free(unsafe.Pointer(cfilename))
	if err := newError(C.yr_rules_load(cfilename,
		&(r.rules.cptr))); err != nil {
		return nil, err
	}
	runtime.SetFinalizer(r.rules, (*rules).finalize)
	return r, nil
}

func (r *rules) finalize() {
	C.yr_rules_destroy(r.cptr)
	runtime.SetFinalizer(r, nil)
}

// Destroy destroys the YARA data structure representing a ruleset.
// Since a Finalizer for the underlying YR_RULES structure is
// automatically set up on creation, it should not be necessary to
// explicitly call this method.
func (r *Rules) Destroy() {
	if r.rules != nil {
		r.rules.finalize()
		r.rules = nil
	}
}

// DefineVariable defines a named variable for use by the compiler.
// Boolean, int64, float64, and string types are supported.
func (r *Rules) DefineVariable(identifier string, value interface{}) (err error) {
	cid := C.CString(identifier)
	defer C.free(unsafe.Pointer(cid))
	switch value.(type) {
	case bool:
		var v int
		if value.(bool) {
			v = 1
		}
		err = newError(C.yr_rules_define_boolean_variable(
			r.cptr, cid, C.int(v)))
	case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
		value := toint64(value)
		err = newError(C.yr_rules_define_integer_variable(
			r.cptr, cid, C.int64_t(value)))
	case float64:
		err = newError(C.yr_rules_define_float_variable(
			r.cptr, cid, C.double(value.(float64))))
	case string:
		cvalue := C.CString(value.(string))
		defer C.free(unsafe.Pointer(cvalue))
		err = newError(C.yr_rules_define_string_variable(
			r.cptr, cid, cvalue))
	default:
		err = errors.New("wrong value type passed to DefineVariable; bool, int64, float64, string are accepted")
	}
	keepAlive(r)
	return
}

// GetRules returns a slice of rule objects that are part of the
// ruleset
// GetRules returns a slice of rule objects that are part of the
// ruleset.
func (r *Rules) GetRules() (rules []Rule) {
	var size C.int
	C.get_rules(r.cptr, nil, &size)
	if size == 0 {
		return
	}
	ptrs := make([]*C.YR_RULE, int(size))
	C.get_rules(r.cptr, &ptrs[0], &size)
	for _, ptr := range ptrs {
		rules = append(rules, Rule{ptr})
	}
	return
}
<|endoftext|>


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

// Package factotum encapsulates crypto operations on user's public/private keys.
package factotum

import (
	"crypto/ecdsa"
	"crypto/elliptic"
	"crypto/rand"
	"crypto/sha256"
	"fmt"
	"io/ioutil"
	"math/big"
	"os"
	"path/filepath"
	"strings"
	"u-old/log"

	"upspin.io/errors"
	"upspin.io/upspin"
)

type factotumKey struct {
	keyHash      []byte
	public       upspin.PublicKey
	private      string
	ecdsaKeyPair ecdsa.PrivateKey // ecdsa form of key pair
	curveName    string
}

type keyHashArray [sha256.Size]byte

type factotum struct {
	current  keyHashArray
	previous keyHashArray
	keys     map[keyHashArray]factotumKey
}

var _ upspin.Factotum = factotum{}

var sig0 upspin.Signature // for returning nil

// KeyHash returns the hash of a key, given in string format.
func KeyHash(p upspin.PublicKey) []byte {
	keyHash := sha256.Sum256([]byte(p))
	return keyHash[:]
}

// New returns a new Factotum providing all needed private key operations,
// loading keys from dir/*.upspinkey.
// Our desired end state is that Factotum is implemented on each platform by the
// best local means of protecting private keys.  Please do not break the abstraction
// by hand coding direct generation or use of private keys.
func New(dir string) (upspin.Factotum, error) {
	op := "NewFactotum"
	privBytes, err := readFile(op, dir, "secret.upspinkey")
	if err != nil {
		return nil, err
	}
	pubBytes, err := readFile(op, dir, "public.upspinkey")
	if err != nil {
		return nil, err
	}
	pfk, err := makeKey(upspin.PublicKey(pubBytes), string(privBytes))
	if err != nil {
		return nil, err
	}
	fm := make(map[keyHashArray]factotumKey)
	var h keyHashArray
	copy(h[:], pfk.keyHash)
	log.Debug.Printf("factotum %x %q\n", h, pubBytes)
	fm[h] = *pfk
	f := &factotum{
		current:  h,
		previous: h,
		keys:     fm,
	}

	// Read older key pairs.
	// Current file format is "# EE date" concatenated with old public.upspinkey
	// then old secret.upspinkey, and repeat.  This should be cleaned up someday
	// when we have a better idea of what other kinds of keys we need to save.
	// For now, it is cavalier about bailing out at first little mistake.
	s2, err := readFile(op, dir, "secret2.upspinkey")
	if err != nil {
		return f, nil
	}
	lines := strings.Split(string(s2), "\n")
	for {
		if len(lines) < 5 {
			break // This is not enough for a complete key pair.
		}
		if lines[0] != "# EE " {
			break // This is not a kind of key we recognize.
		}
		// lines[0] "# EE "     Joe's key
		// lines[1] "p256"
		// lines[2] "1042...6334" public X
		// lines[3] "2694...192"  public Y
		// lines[4] "8220...5934" private D
		pfk, err := makeKey(upspin.PublicKey(lines[1]+"\n"+lines[2]+"\n"+lines[3]+"\n"), lines[4])
		if err != nil {
			break
		}
		var h keyHashArray
		copy(h[:], pfk.keyHash)
		log.Debug.Printf("factotum %x %q\n", h, lines[1]+"\n"+lines[2]+"\n"+lines[3]+"\n")
		_, ok := f.keys[h]
		if ok { // Duplicate.
			continue // TODO Should we warn?
		}
		f.keys[h] = *pfk
		f.previous = h
		lines = lines[5:]
	}
	return f, err
}

// makeKey creates a factotumKey by filling in the derived fields.
func makeKey(pub upspin.PublicKey, priv string) (*factotumKey, error) {
	ePublicKey, curveName, err := ParsePublicKey(pub)
	// TODO(ehg) sanity check that priv is consistent with pub
	if err != nil {
		return nil, err
	}
	ecdsaKeyPair, err := parsePrivateKey(ePublicKey, priv)
	if err != nil {
		return nil, err
	}
	fk := factotumKey{
		keyHash:      KeyHash(pub),
		public:       pub,
		private:      priv,
		ecdsaKeyPair: *ecdsaKeyPair,
		curveName:    curveName,
	}
	return &fk, nil
}

// FileSign ECDSA-signs c|n|t|dkey|hash, as required for EEPack.
func (f factotum) FileSign(n upspin.PathName, t upspin.Time, dkey, hash []byte) (upspin.Signature, error) {
	fk := f.keys[f.current]
	r, s, err := ecdsa.Sign(rand.Reader, &fk.ecdsaKeyPair, VerHash(fk.curveName, n, t, dkey, hash))
	if err != nil {
		return sig0, err
	}
	return upspin.Signature{R: r, S: s}, nil
}

// ScalarMult is the bare private key operator, used in unwrapping packed data.
func (f factotum) ScalarMult(keyHash []byte, curve elliptic.Curve, x, y *big.Int) (sx, sy *big.Int, err error) {
	var h keyHashArray
	copy(h[:], keyHash)
	fk, ok := f.keys[h]
	if !ok {
		err = errors.E("scalarMult", errors.Errorf("no such key %x", keyHash))
	} else {
		sx, sy = curve.ScalarMult(x, y, fk.ecdsaKeyPair.D.Bytes())
	}
	return
}

// UserSign assists in authenticating to Upspin servers.
func (f factotum) UserSign(hash []byte) (upspin.Signature, error) {
	// no logging or constraining hash, because will change to TokenBinding anyway
	fk := f.keys[f.current]
	r, s, err := ecdsa.Sign(rand.Reader, &fk.ecdsaKeyPair, hash)
	if err != nil {
		return sig0, err
	}
	return upspin.Signature{R: r, S: s}, nil
}

// Pop derives a Factotum by switching default from the current to the previous key.
func (f factotum) Pop() upspin.Factotum {
	// Arbitrarily keep f.previous unchanged, so Pop() is idempotent.
	// We don't yet have any need to go further back in time.
	return &factotum{current: f.previous, previous: f.previous, keys: f.keys}
}

// PublicKey returns the user's latest public key.
func (f factotum) PublicKey() upspin.PublicKey {
	return f.keys[f.current].public
}

// PublicKeyFromHash returns the user's public key with matching keyHash.
func (f factotum) PublicKeyFromHash(keyHash []byte) (upspin.PublicKey, error) {
	if keyHash == nil || len(keyHash) == 0 {
		return "", errors.Errorf("invalid keyHash")
	}
	var h keyHashArray
	copy(h[:], keyHash)
	fk, ok := f.keys[h]
	if !ok {
		return "", errors.Errorf("no such key")
	}
	return fk.public, nil
}

// VerHash provides the basis for signing and verifying files.
func VerHash(curveName string, pathname upspin.PathName, time upspin.Time, dkey, cipherSum []byte) []byte {
	b := sha256.Sum256([]byte(fmt.Sprintf("%02x:%s:%d:%x:%x", curveName, pathname, time, dkey, cipherSum)))
	return b[:]
}

// parsePrivateKey returns an ECDSA private key given a user's ECDSA public key and a
// string representation of the private key.
func parsePrivateKey(publicKey *ecdsa.PublicKey, privateKey string) (priv *ecdsa.PrivateKey, err error) {
	privateKey = strings.TrimSpace(string(privateKey))
	var d big.Int
	err = d.UnmarshalText([]byte(privateKey))
	if err != nil {
		return nil, err
	}
	return &ecdsa.PrivateKey{PublicKey: *publicKey, D: &d}, nil
}

// ParsePublicKey takes an Upspin representation of a public key and converts it into an ECDSA public key, returning its type.
// The Upspin string representation uses \n as newline no matter what native OS it runs on.
func ParsePublicKey(public upspin.PublicKey) (*ecdsa.PublicKey, string, error) {
	fields := strings.Split(string(public), "\n")
	if len(fields) != 4 { // 4 is because string should be terminated by \n, hence fields[3]==""
		return nil, "", errors.E("ParsePublicKey", errors.Invalid, errors.Errorf("expected keytype, two big ints and a newline; got %d %v", len(fields), fields))
	}
	keyType := fields[0]
	var x, y big.Int
	_, ok := x.SetString(fields[1], 10)
	if !ok {
		return nil, "", errors.E("ParsePublicKey", errors.Invalid, errors.Errorf("%s is not a big int", fields[1]))
	}
	_, ok = y.SetString(fields[2], 10)
	if !ok {
		return nil, "", errors.E("ParsePublicKey", errors.Invalid, errors.Errorf("%s is not a big int", fields[2]))
	}

	var curve elliptic.Curve
	switch keyType {
	case "p256":
		curve = elliptic.P256()
	case "p521":
		curve = elliptic.P521()
	case "p384":
		curve = elliptic.P384()
	default:
		return nil, "", errors.Errorf("unknown key type: %q", keyType)
	}
	return &ecdsa.PublicKey{Curve: curve, X: &x, Y: &y}, keyType, nil
}

func readFile(op, dir, name string) ([]byte, error) {
	b, err := ioutil.ReadFile(filepath.Join(dir, name))
	if os.IsNotExist(err) {
		return nil, errors.E(op, errors.NotExist, err)
	}
	if err != nil {
		return nil, errors.E(op, errors.IO, err)
	}
	return b, nil
}
<commit_msg>factotum:  fix goimports issue<commit_after>// Copyright 2016 The Upspin Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package factotum encapsulates crypto operations on user's public/private keys.
package factotum

import (
	"crypto/ecdsa"
	"crypto/elliptic"
	"crypto/rand"
	"crypto/sha256"
	"fmt"
	"io/ioutil"
	"math/big"
	"os"
	"path/filepath"
	"strings"

	"upspin.io/errors"
	"upspin.io/log"
	"upspin.io/upspin"
)

type factotumKey struct {
	keyHash      []byte
	public       upspin.PublicKey
	private      string
	ecdsaKeyPair ecdsa.PrivateKey // ecdsa form of key pair
	curveName    string
}

type keyHashArray [sha256.Size]byte

type factotum struct {
	current  keyHashArray
	previous keyHashArray
	keys     map[keyHashArray]factotumKey
}

var _ upspin.Factotum = factotum{}

var sig0 upspin.Signature // for returning nil

// KeyHash returns the hash of a key, given in string format.
func KeyHash(p upspin.PublicKey) []byte {
	keyHash := sha256.Sum256([]byte(p))
	return keyHash[:]
}

// New returns a new Factotum providing all needed private key operations,
// loading keys from dir/*.upspinkey.
// Our desired end state is that Factotum is implemented on each platform by the
// best local means of protecting private keys.  Please do not break the abstraction
// by hand coding direct generation or use of private keys.
func New(dir string) (upspin.Factotum, error) {
	op := "NewFactotum"
	privBytes, err := readFile(op, dir, "secret.upspinkey")
	if err != nil {
		return nil, err
	}
	pubBytes, err := readFile(op, dir, "public.upspinkey")
	if err != nil {
		return nil, err
	}
	pfk, err := makeKey(upspin.PublicKey(pubBytes), string(privBytes))
	if err != nil {
		return nil, err
	}
	fm := make(map[keyHashArray]factotumKey)
	var h keyHashArray
	copy(h[:], pfk.keyHash)
	log.Debug.Printf("factotum %x %q\n", h, pubBytes)
	fm[h] = *pfk
	f := &factotum{
		current:  h,
		previous: h,
		keys:     fm,
	}

	// Read older key pairs.
	// Current file format is "# EE date" concatenated with old public.upspinkey
	// then old secret.upspinkey, and repeat.  This should be cleaned up someday
	// when we have a better idea of what other kinds of keys we need to save.
	// For now, it is cavalier about bailing out at first little mistake.
	s2, err := readFile(op, dir, "secret2.upspinkey")
	if err != nil {
		return f, nil
	}
	lines := strings.Split(string(s2), "\n")
	for {
		if len(lines) < 5 {
			break // This is not enough for a complete key pair.
		}
		if lines[0] != "# EE " {
			break // This is not a kind of key we recognize.
		}
		// lines[0] "# EE "     Joe's key
		// lines[1] "p256"
		// lines[2] "1042...6334" public X
		// lines[3] "2694...192"  public Y
		// lines[4] "8220...5934" private D
		pfk, err := makeKey(upspin.PublicKey(lines[1]+"\n"+lines[2]+"\n"+lines[3]+"\n"), lines[4])
		if err != nil {
			break
		}
		var h keyHashArray
		copy(h[:], pfk.keyHash)
		log.Debug.Printf("factotum %x %q\n", h, lines[1]+"\n"+lines[2]+"\n"+lines[3]+"\n")
		_, ok := f.keys[h]
		if ok { // Duplicate.
			continue // TODO Should we warn?
		}
		f.keys[h] = *pfk
		f.previous = h
		lines = lines[5:]
	}
	return f, err
}

// makeKey creates a factotumKey by filling in the derived fields.
func makeKey(pub upspin.PublicKey, priv string) (*factotumKey, error) {
	ePublicKey, curveName, err := ParsePublicKey(pub)
	// TODO(ehg) sanity check that priv is consistent with pub
	if err != nil {
		return nil, err
	}
	ecdsaKeyPair, err := parsePrivateKey(ePublicKey, priv)
	if err != nil {
		return nil, err
	}
	fk := factotumKey{
		keyHash:      KeyHash(pub),
		public:       pub,
		private:      priv,
		ecdsaKeyPair: *ecdsaKeyPair,
		curveName:    curveName,
	}
	return &fk, nil
}

// FileSign ECDSA-signs c|n|t|dkey|hash, as required for EEPack.
func (f factotum) FileSign(n upspin.PathName, t upspin.Time, dkey, hash []byte) (upspin.Signature, error) {
	fk := f.keys[f.current]
	r, s, err := ecdsa.Sign(rand.Reader, &fk.ecdsaKeyPair, VerHash(fk.curveName, n, t, dkey, hash))
	if err != nil {
		return sig0, err
	}
	return upspin.Signature{R: r, S: s}, nil
}

// ScalarMult is the bare private key operator, used in unwrapping packed data.
func (f factotum) ScalarMult(keyHash []byte, curve elliptic.Curve, x, y *big.Int) (sx, sy *big.Int, err error) {
	var h keyHashArray
	copy(h[:], keyHash)
	fk, ok := f.keys[h]
	if !ok {
		err = errors.E("scalarMult", errors.Errorf("no such key %x", keyHash))
	} else {
		sx, sy = curve.ScalarMult(x, y, fk.ecdsaKeyPair.D.Bytes())
	}
	return
}

// UserSign assists in authenticating to Upspin servers.
func (f factotum) UserSign(hash []byte) (upspin.Signature, error) {
	// no logging or constraining hash, because will change to TokenBinding anyway
	fk := f.keys[f.current]
	r, s, err := ecdsa.Sign(rand.Reader, &fk.ecdsaKeyPair, hash)
	if err != nil {
		return sig0, err
	}
	return upspin.Signature{R: r, S: s}, nil
}

// Pop derives a Factotum by switching default from the current to the previous key.
func (f factotum) Pop() upspin.Factotum {
	// Arbitrarily keep f.previous unchanged, so Pop() is idempotent.
	// We don't yet have any need to go further back in time.
	return &factotum{current: f.previous, previous: f.previous, keys: f.keys}
}

// PublicKey returns the user's latest public key.
func (f factotum) PublicKey() upspin.PublicKey {
	return f.keys[f.current].public
}

// PublicKeyFromHash returns the user's public key with matching keyHash.
func (f factotum) PublicKeyFromHash(keyHash []byte) (upspin.PublicKey, error) {
	if keyHash == nil || len(keyHash) == 0 {
		return "", errors.Errorf("invalid keyHash")
	}
	var h keyHashArray
	copy(h[:], keyHash)
	fk, ok := f.keys[h]
	if !ok {
		return "", errors.Errorf("no such key")
	}
	return fk.public, nil
}

// VerHash provides the basis for signing and verifying files.
func VerHash(curveName string, pathname upspin.PathName, time upspin.Time, dkey, cipherSum []byte) []byte {
	b := sha256.Sum256([]byte(fmt.Sprintf("%02x:%s:%d:%x:%x", curveName, pathname, time, dkey, cipherSum)))
	return b[:]
}

// parsePrivateKey returns an ECDSA private key given a user's ECDSA public key and a
// string representation of the private key.
func parsePrivateKey(publicKey *ecdsa.PublicKey, privateKey string) (priv *ecdsa.PrivateKey, err error) {
	privateKey = strings.TrimSpace(string(privateKey))
	var d big.Int
	err = d.UnmarshalText([]byte(privateKey))
	if err != nil {
		return nil, err
	}
	return &ecdsa.PrivateKey{PublicKey: *publicKey, D: &d}, nil
}

// ParsePublicKey takes an Upspin representation of a public key and converts it into an ECDSA public key, returning its type.
// The Upspin string representation uses \n as newline no matter what native OS it runs on.
func ParsePublicKey(public upspin.PublicKey) (*ecdsa.PublicKey, string, error) {
	fields := strings.Split(string(public), "\n")
	if len(fields) != 4 { // 4 is because string should be terminated by \n, hence fields[3]==""
		return nil, "", errors.E("ParsePublicKey", errors.Invalid, errors.Errorf("expected keytype, two big ints and a newline; got %d %v", len(fields), fields))
	}
	keyType := fields[0]
	var x, y big.Int
	_, ok := x.SetString(fields[1], 10)
	if !ok {
		return nil, "", errors.E("ParsePublicKey", errors.Invalid, errors.Errorf("%s is not a big int", fields[1]))
	}
	_, ok = y.SetString(fields[2], 10)
	if !ok {
		return nil, "", errors.E("ParsePublicKey", errors.Invalid, errors.Errorf("%s is not a big int", fields[2]))
	}

	var curve elliptic.Curve
	switch keyType {
	case "p256":
		curve = elliptic.P256()
	case "p521":
		curve = elliptic.P521()
	case "p384":
		curve = elliptic.P384()
	default:
		return nil, "", errors.Errorf("unknown key type: %q", keyType)
	}
	return &ecdsa.PublicKey{Curve: curve, X: &x, Y: &y}, keyType, nil
}

func readFile(op, dir, name string) ([]byte, error) {
	b, err := ioutil.ReadFile(filepath.Join(dir, name))
	if os.IsNotExist(err) {
		return nil, errors.E(op, errors.NotExist, err)
	}
	if err != nil {
		return nil, errors.E(op, errors.IO, err)
	}
	return b, nil
}
<|endoftext|>


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

package main

import (
	"code.google.com/p/go.tools/importer"
	"code.google.com/p/go.tools/oracle"
	"encoding/json"
	"github.com/fzipp/pythia/static"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"sort"
	"strings"
	"time"
)

func serveList(w http.ResponseWriter, req *http.Request) {
	err := listView.Execute(w, struct {
		Scope    string
		Packages []*importer.PackageInfo
	}{
		Scope:    strings.Join(args, " "),
		Packages: packages,
	})
	if err != nil {
		log.Println(err)
	}
}

func serveSource(w http.ResponseWriter, req *http.Request) {
	file := req.FormValue("file")
	if isForbidden(file) {
		errorForbidden(w)
		return
	}
	sourceView.Execute(w, file)
}

func serveFile(w http.ResponseWriter, req *http.Request) {
	path := req.FormValue("path")
	if isForbidden(path) {
		errorForbidden(w)
		return
	}
	content, err := ioutil.ReadFile(path)
	if err != nil {
		log.Println(req.RemoteAddr, err)
		http.NotFound(w, req)
		return
	}
	w.Write(content)
}

func isForbidden(path string) bool {
	i := sort.SearchStrings(files, path)
	return i >= len(files) || files[i] != path
}

func errorForbidden(w http.ResponseWriter) {
	http.Error(w, "Forbidden", 403)
}

func serveQuery(w http.ResponseWriter, req *http.Request) {
	mode := req.FormValue("mode")
	pos := req.FormValue("pos")
	format := req.FormValue("format")
	if *verbose {
		log.Println(req.RemoteAddr, cmdLine(mode, pos, format))
	}
	qpos, err := oracle.ParseQueryPos(imp, pos, false)
	if err != nil {
		io.WriteString(w, err.Error())
		return
	}
	mutex.Lock()
	res, err := ora.Query(mode, qpos)
	mutex.Unlock()
	if err != nil {
		io.WriteString(w, err.Error())
		return
	}
	writeResult(w, res, format)
}

func writeResult(w io.Writer, res *oracle.Result, format string) {
	if format == "json" {
		b, err := json.Marshal(res)
		if err != nil {
			io.WriteString(w, err.Error())
			return
		}
		w.Write(b)
		return
	}
	res.WriteTo(w)
}

func serveStatic(w http.ResponseWriter, req *http.Request) {
	name := req.URL.Path
	data, ok := static.Files[name]
	if !ok {
		http.NotFound(w, req)
		return
	}
	http.ServeContent(w, req, name, time.Time{}, strings.NewReader(data))
}
<commit_msg>add error check<commit_after>// Copyright 2013 Frederik Zipp.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"code.google.com/p/go.tools/importer"
	"code.google.com/p/go.tools/oracle"
	"encoding/json"
	"github.com/fzipp/pythia/static"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"sort"
	"strings"
	"time"
)

func serveList(w http.ResponseWriter, req *http.Request) {
	err := listView.Execute(w, struct {
		Scope    string
		Packages []*importer.PackageInfo
	}{
		Scope:    strings.Join(args, " "),
		Packages: packages,
	})
	if err != nil {
		log.Println(err)
	}
}

func serveSource(w http.ResponseWriter, req *http.Request) {
	file := req.FormValue("file")
	if isForbidden(file) {
		errorForbidden(w)
		return
	}
	err := sourceView.Execute(w, file)
	if err != nil {
		log.Println(err)
	}
}

func serveFile(w http.ResponseWriter, req *http.Request) {
	path := req.FormValue("path")
	if isForbidden(path) {
		errorForbidden(w)
		return
	}
	content, err := ioutil.ReadFile(path)
	if err != nil {
		log.Println(req.RemoteAddr, err)
		http.NotFound(w, req)
		return
	}
	w.Write(content)
}

func isForbidden(path string) bool {
	i := sort.SearchStrings(files, path)
	return i >= len(files) || files[i] != path
}

func errorForbidden(w http.ResponseWriter) {
	http.Error(w, "Forbidden", 403)
}

func serveQuery(w http.ResponseWriter, req *http.Request) {
	mode := req.FormValue("mode")
	pos := req.FormValue("pos")
	format := req.FormValue("format")
	if *verbose {
		log.Println(req.RemoteAddr, cmdLine(mode, pos, format))
	}
	qpos, err := oracle.ParseQueryPos(imp, pos, false)
	if err != nil {
		io.WriteString(w, err.Error())
		return
	}
	mutex.Lock()
	res, err := ora.Query(mode, qpos)
	mutex.Unlock()
	if err != nil {
		io.WriteString(w, err.Error())
		return
	}
	writeResult(w, res, format)
}

func writeResult(w io.Writer, res *oracle.Result, format string) {
	if format == "json" {
		b, err := json.Marshal(res)
		if err != nil {
			io.WriteString(w, err.Error())
			return
		}
		w.Write(b)
		return
	}
	res.WriteTo(w)
}

func serveStatic(w http.ResponseWriter, req *http.Request) {
	name := req.URL.Path
	data, ok := static.Files[name]
	if !ok {
		http.NotFound(w, req)
		return
	}
	http.ServeContent(w, req, name, time.Time{}, strings.NewReader(data))
}
<|endoftext|>


<commit_before>// +build !appengine

package goji

import (
	"crypto/tls"
	"flag"
	"log"
	"net"
	"net/http"
	"time"

	"github.com/zenazn/goji/bind"
	"github.com/zenazn/goji/graceful"
)

func init() {
	bind.WithFlag()
	if fl := log.Flags(); fl&log.Ltime != 0 {
		log.SetFlags(fl | log.Lmicroseconds)
	}
	graceful.DoubleKickWindow(2 * time.Second)
}

// Serve starts Goji using reasonable defaults.
func Serve() {
	ServeListener(bind.Default())
}

// Like Serve, but enables TLS using the given config.
func ServeTLS(config *tls.Config) {
	ServeListener(tls.NewListener(bind.Default(), config))
}

// Like Serve, but runs Goji on top of an arbitrary net.Listener.
func ServeListener(listener net.Listener) {
	if !flag.Parsed() {
		flag.Parse()
	}

	DefaultMux.Compile()
	// Install our handler at the root of the standard net/http default mux.
	// This allows packages like expvar to continue working as expected.
	http.Handle("/", DefaultMux)

	log.Println("Starting Goji on", listener.Addr())

	graceful.HandleSignals()
	bind.Ready()
	graceful.PreHook(func() { log.Printf("Goji received signal, gracefully stopping") })
	graceful.PostHook(func() { log.Printf("Goji stopped") })

	err := graceful.Serve(listener, http.DefaultServeMux)

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

	graceful.Wait()
}
<commit_msg>Ensure flags are parsed before calling bind.Default().<commit_after>// +build !appengine

package goji

import (
	"crypto/tls"
	"flag"
	"log"
	"net"
	"net/http"
	"time"

	"github.com/zenazn/goji/bind"
	"github.com/zenazn/goji/graceful"
)

func init() {
	bind.WithFlag()
	if fl := log.Flags(); fl&log.Ltime != 0 {
		log.SetFlags(fl | log.Lmicroseconds)
	}
	graceful.DoubleKickWindow(2 * time.Second)
}

// Serve starts Goji using reasonable defaults.
func Serve() {
	if !flag.Parsed() {
		flag.Parse()
	}

	ServeListener(bind.Default())
}

// Like Serve, but enables TLS using the given config.
func ServeTLS(config *tls.Config) {
	if !flag.Parsed() {
		flag.Parse()
	}

	ServeListener(tls.NewListener(bind.Default(), config))
}

// Like Serve, but runs Goji on top of an arbitrary net.Listener.
func ServeListener(listener net.Listener) {
	DefaultMux.Compile()
	// Install our handler at the root of the standard net/http default mux.
	// This allows packages like expvar to continue working as expected.
	http.Handle("/", DefaultMux)

	log.Println("Starting Goji on", listener.Addr())

	graceful.HandleSignals()
	bind.Ready()
	graceful.PreHook(func() { log.Printf("Goji received signal, gracefully stopping") })
	graceful.PostHook(func() { log.Printf("Goji stopped") })

	err := graceful.Serve(listener, http.DefaultServeMux)

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

	graceful.Wait()
}
<|endoftext|>


<commit_before>package swp

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"io"
	"os"
	"testing"
	"time"

	cv "github.com/glycerine/goconvey/convey"
	"github.com/glycerine/hnatsd/server"
)

func Test040FileTransfer(t *testing.T) {

	cv.Convey("Big file transfer should succeed.", t, func() {

		// ===============================
		// begin generic nats setup
		// ===============================

		host := "127.0.0.1"
		port := getAvailPort()
		gnats := StartGnatsd(host, port)
		defer func() {
			p("calling gnats.Shutdown()")
			gnats.Shutdown() // when done
		}()

		//n := 160 // 16MB file was causing fail.
		n := 1 << 24 // 16MB file was causing fail.
		writeme := SequentialPayload(int64(n))

		p("writeme is")
		showSeq(writeme, 100000)
		//showSeq(writeme, 10)

		var buf bytes.Buffer
		recDone := make(chan bool)
		go testrec(host, port, gnats, &buf, recDone)
		testsender(host, port, gnats, writeme)
		<-recDone
		p("bytes transfered %v", len(buf.Bytes()))
		got := buf.Bytes()

		p("got is")
		showSeq(got, 100000)
		//showSeq(got, 10)

		cv.So(len(got), cv.ShouldResemble, len(writeme))
		firstDiff := -1
		for i := 0; i < len(got); i++ {
			if got[i] != writeme[i] {
				firstDiff = i
				break
			}
		}
		if firstDiff != -1 {
			p("first Diff at %v, got %v, expected %v", firstDiff, got[firstDiff], writeme[firstDiff])
			a, b, c := nearestOctet(firstDiff, got)
			wa, wb, wc := nearestOctet(firstDiff, writeme)
			p("first Diff at %v for got: [%v, %v, %v]; for writem: [%v, %v, %v]", firstDiff, a, b, c, wa, wb, wc)
		}
		cv.So(firstDiff, cv.ShouldResemble, -1)
	})

}

func testsender(host string, nport int, gnats *server.Server, writeme []byte) {

	// ===============================
	// setup nats client for a publisher
	// ===============================

	skipTLS := true
	asyncErrCrash := false
	pubC := NewNatsClientConfig(host, nport, "A", "A", skipTLS, asyncErrCrash)
	pub := NewNatsClient(pubC)
	err := pub.Start()
	panicOn(err)
	defer pub.Close()

	// ===============================
	// make a session for each
	// ===============================

	anet := NewNatsNet(pub)

	//fmt.Printf("pub = %#v\n", pub)

	to := time.Millisecond * 100
	windowby := int64(1 << 20)
	//windowby := int64(10)
	A, err := NewSession(SessionConfig{Net: anet, LocalInbox: "A", DestInbox: "B",
		WindowMsgCount: 1000, WindowByteSz: windowby, Timeout: to, Clk: RealClk})
	panicOn(err)

	//rep := ReportOnSubscription(pub.Scrip)
	//fmt.Printf("rep = %#v\n", rep)

	msgLimit := int64(1000)
	bytesLimit := int64(600000)
	//bytesLimit := int64(10)
	A.Swp.Sender.FlowCt = &FlowCtrl{Flow: Flow{
		ReservedByteCap: 600000,
		ReservedMsgCap:  1000,
	}}
	SetSubscriptionLimits(pub.Scrip, msgLimit, bytesLimit)

	// writer does:
	/*
		        buf := make([]byte, 1<<20)
				// copy stdin over the wire
				for {
					_, err = io.CopyBuffer(A, os.Stdin, buf)
					if err == io.ErrShortWrite {
						continue
					} else {
						break
					}
				}
				//panicOn(err)
	*/

	//	by, err := ioutil.ReadAll(os.Stdin)
	//	panicOn(err)
	//	fmt.Fprintf(os.Stderr, "read %v bytes from stdin\n", len(by))

	n, err := A.Write(writeme)
	fmt.Fprintf(os.Stderr, "n = %v, err=%v after A.Write(writeme), where len(writeme)=%v\n", n, err, len(writeme))
	A.Stop()
}

func testrec(host string, nport int, gnats *server.Server, dest io.Writer, done chan bool) {

	// ===============================
	// setup nats client for a subscriber
	// ===============================

	subC := NewNatsClientConfig(host, nport, "B", "B", true, false)
	sub := NewNatsClient(subC)
	err := sub.Start()
	panicOn(err)
	defer sub.Close()

	// ===============================
	// make a session for each
	// ===============================
	var bnet *NatsNet

	//fmt.Printf("sub = %#v\n", sub)

	for {
		if bnet != nil {
			bnet.Stop()
		}
		bnet = NewNatsNet(sub)
		//fmt.Printf("recv.go is setting up NewSession...\n")
		to := time.Millisecond * 100
		B, err := NewSession(SessionConfig{Net: bnet, LocalInbox: "B", DestInbox: "A",
			WindowMsgCount: 1000, WindowByteSz: -1, Timeout: to, Clk: RealClk,
			NumFailedKeepAlivesBeforeClosing: -1,
		})
		panicOn(err)

		//rep := ReportOnSubscription(sub.Scrip)
		//fmt.Printf("rep = %#v\n", rep)

		msgLimit := int64(1000)
		bytesLimit := int64(600000)
		//bytesLimit := int64(10)
		B.Swp.Sender.FlowCt = &FlowCtrl{Flow: Flow{
			ReservedByteCap: 600000,
			ReservedMsgCap:  1000,
		}}
		SetSubscriptionLimits(sub.Scrip, msgLimit, bytesLimit)

		senderClosed := make(chan bool)
		B.Swp.Recver.AppCloseCallback = func() {
			p("AppCloseCallback called. B.Swp.Recver.LastFrameClientConsumed=%v",
				B.Swp.Recver.LastFrameClientConsumed)
			close(senderClosed)
		}

		var n, ntot int64
		var expectedSeqNum int64
		for {
			fmt.Printf("\n ... about to receive on B.ReadMessagesCh %p\n", B.ReadMessagesCh)
			select {
			case seq := <-B.ReadMessagesCh:
				ns := len(seq.Seq)
				fmt.Fprintf(os.Stderr, "\n B filetransfer_test testrec() got sequence len %v from B.ReadMessagesCh. SeqNum:[%v, %v]\n", ns, seq.Seq[0].SeqNum, seq.Seq[ns-1].SeqNum)
				for k, pk := range seq.Seq {
					if pk.SeqNum != expectedSeqNum {
						panic(fmt.Sprintf(
							"expected SeqNum %v, but got %v",
							expectedSeqNum, pk.SeqNum))
					}
					expectedSeqNum++
					// copy to dest, handling short writes only.
					var from int64
					for {
						n, err = io.Copy(dest, bytes.NewBuffer(pk.Data[from:]))
						fmt.Fprintf(os.Stderr, "\n %v-th io.Copy gave n=%v, err=%v\n", k, n, err)
						ntot += n
						if err == io.ErrShortWrite {
							p("hanlding io.ErrShortWrite in copy loop")
							from += n
							continue
						} else {
							break
						}
					}
					panicOn(err)
					//fmt.Printf("\n")
					fmt.Fprintf(os.Stderr, "\ndone with latest io.Copy, err was nil. n=%v, ntot=%v\n", n, ntot)
				}
			case <-B.Halt.Done.Chan:
				fmt.Printf("recv got B.Done\n")
				close(done)
				return

			case <-senderClosed:
				fmt.Printf("recv got senderClosed\n")
				close(done)
				return

				// ridiculous end-of-transfer indicator, but for debugging...
				//			case <-time.After(4 * time.Second):
				//				fmt.Printf("debug: recv loop timeout after 4 sec\n")
				//				close(done)
				//				return
			}
		}
	}
}

func SequentialPayload(n int64) []byte {
	if n%8 != 0 {
		panic(fmt.Sprintf("n == %v must be a multiple of 8; has remainder %v", n, n%8))
	}

	k := uint64(n / 8)
	by := make([]byte, n)
	j := uint64(0)
	for i := uint64(0); i < k; i++ {
		j = i * 8
		binary.LittleEndian.PutUint64(by[j:j+8], j)
	}
	return by
}

func nearestOctet(pos int, by []byte) (a, b, c int64) {
	n := len(by)
	pos -= (pos % 8)
	if pos-8 >= 0 && pos < n {
		a = int64(binary.LittleEndian.Uint64(by[pos-8 : pos]))
	}
	if pos >= 0 && pos+8 < n {
		b = int64(binary.LittleEndian.Uint64(by[pos : pos+8]))
	}
	if pos+8 >= 0 && pos+16 < n {
		c = int64(binary.LittleEndian.Uint64(by[pos+8 : pos+16]))
	}
	return a, b, c
}

func showSeq(by []byte, m int) {
	//fmt.Printf("showSeq called with len(by)=%v, m=%v\n", len(by), m)
	fmt.Printf("\n")
	n := len(by)
	if n%8 != 0 {
		panic(fmt.Sprintf("len(by) == n == %v must be a multiple of 8; has remainder %v", n, n%8))
	}
	for i := 0; i*8+8 <= n; i = i + m {
		j := i * 8
		//p("i = %v.  j=%v. m=%v. n=%v. len(by)=%v.  (i+8)*8+8=%v <= n(%v) is %v", i, j, m, n, len(by), (i+m)*8+8, n, (i+m)*8+8 <= n)
		a := int64(binary.LittleEndian.Uint64(by[j : j+8]))
		fmt.Printf("at %08d: %08d\n", j, a)
		if a != int64(j) {
			panic(fmt.Sprintf("detected j != a, at j=%v, a=%v", int64(j), a))
		}
	}
}

func Test041File(t *testing.T) {

	cv.Convey("SequentialPayload() produces a byte-numbered octet payload", t, func() {
		for i := 8; i < 128; i += 8 {
			by := SequentialPayload(int64(i))
			showSeq(by, 1)
		}
	})
}
<commit_msg>atg. quiet down<commit_after>package swp

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"io"
	"os"
	"testing"
	"time"

	cv "github.com/glycerine/goconvey/convey"
	"github.com/glycerine/hnatsd/server"
)

func Test040FileTransfer(t *testing.T) {

	cv.Convey("Big file transfer should succeed.", t, func() {

		// ===============================
		// begin generic nats setup
		// ===============================

		host := "127.0.0.1"
		port := getAvailPort()
		gnats := StartGnatsd(host, port)
		defer func() {
			p("calling gnats.Shutdown()")
			gnats.Shutdown() // when done
		}()

		//n := 160 // 16MB file was causing fail.
		n := 1 << 24 // 16MB file was causing fail.
		writeme := SequentialPayload(int64(n))

		p("writeme is")
		showSeq(writeme, 100000)
		//showSeq(writeme, 10)

		var buf bytes.Buffer
		recDone := make(chan bool)
		go testrec(host, port, gnats, &buf, recDone)
		testsender(host, port, gnats, writeme)
		<-recDone
		p("bytes transfered %v", len(buf.Bytes()))
		got := buf.Bytes()

		p("got is")
		showSeq(got, 100000)
		//showSeq(got, 10)

		cv.So(len(got), cv.ShouldResemble, len(writeme))
		firstDiff := -1
		for i := 0; i < len(got); i++ {
			if got[i] != writeme[i] {
				firstDiff = i
				break
			}
		}
		if firstDiff != -1 {
			p("first Diff at %v, got %v, expected %v", firstDiff, got[firstDiff], writeme[firstDiff])
			a, b, c := nearestOctet(firstDiff, got)
			wa, wb, wc := nearestOctet(firstDiff, writeme)
			p("first Diff at %v for got: [%v, %v, %v]; for writem: [%v, %v, %v]", firstDiff, a, b, c, wa, wb, wc)
		}
		cv.So(firstDiff, cv.ShouldResemble, -1)
	})

}

func testsender(host string, nport int, gnats *server.Server, writeme []byte) {

	// ===============================
	// setup nats client for a publisher
	// ===============================

	skipTLS := true
	asyncErrCrash := false
	pubC := NewNatsClientConfig(host, nport, "A", "A", skipTLS, asyncErrCrash)
	pub := NewNatsClient(pubC)
	err := pub.Start()
	panicOn(err)
	defer pub.Close()

	// ===============================
	// make a session for each
	// ===============================

	anet := NewNatsNet(pub)

	//fmt.Printf("pub = %#v\n", pub)

	to := time.Millisecond * 100
	windowby := int64(1 << 20)
	//windowby := int64(10)
	A, err := NewSession(SessionConfig{Net: anet, LocalInbox: "A", DestInbox: "B",
		WindowMsgCount: 1000, WindowByteSz: windowby, Timeout: to, Clk: RealClk})
	panicOn(err)

	//rep := ReportOnSubscription(pub.Scrip)
	//fmt.Printf("rep = %#v\n", rep)

	msgLimit := int64(1000)
	bytesLimit := int64(600000)
	//bytesLimit := int64(10)
	A.Swp.Sender.FlowCt = &FlowCtrl{Flow: Flow{
		ReservedByteCap: 600000,
		ReservedMsgCap:  1000,
	}}
	SetSubscriptionLimits(pub.Scrip, msgLimit, bytesLimit)

	// writer does:
	/*
		        buf := make([]byte, 1<<20)
				// copy stdin over the wire
				for {
					_, err = io.CopyBuffer(A, os.Stdin, buf)
					if err == io.ErrShortWrite {
						continue
					} else {
						break
					}
				}
				//panicOn(err)
	*/

	//	by, err := ioutil.ReadAll(os.Stdin)
	//	panicOn(err)
	//	fmt.Fprintf(os.Stderr, "read %v bytes from stdin\n", len(by))

	n, err := A.Write(writeme)
	fmt.Fprintf(os.Stderr, "n = %v, err=%v after A.Write(writeme), where len(writeme)=%v\n", n, err, len(writeme))
	A.Stop()
}

func testrec(host string, nport int, gnats *server.Server, dest io.Writer, done chan bool) {

	// ===============================
	// setup nats client for a subscriber
	// ===============================

	subC := NewNatsClientConfig(host, nport, "B", "B", true, false)
	sub := NewNatsClient(subC)
	err := sub.Start()
	panicOn(err)
	defer sub.Close()

	// ===============================
	// make a session for each
	// ===============================
	var bnet *NatsNet

	//fmt.Printf("sub = %#v\n", sub)

	for {
		if bnet != nil {
			bnet.Stop()
		}
		bnet = NewNatsNet(sub)
		//fmt.Printf("recv.go is setting up NewSession...\n")
		to := time.Millisecond * 100
		B, err := NewSession(SessionConfig{Net: bnet, LocalInbox: "B", DestInbox: "A",
			WindowMsgCount: 1000, WindowByteSz: -1, Timeout: to, Clk: RealClk,
			NumFailedKeepAlivesBeforeClosing: -1,
		})
		panicOn(err)

		//rep := ReportOnSubscription(sub.Scrip)
		//fmt.Printf("rep = %#v\n", rep)

		msgLimit := int64(1000)
		bytesLimit := int64(600000)
		//bytesLimit := int64(10)
		B.Swp.Sender.FlowCt = &FlowCtrl{Flow: Flow{
			ReservedByteCap: 600000,
			ReservedMsgCap:  1000,
		}}
		SetSubscriptionLimits(sub.Scrip, msgLimit, bytesLimit)

		senderClosed := make(chan bool)
		B.Swp.Recver.AppCloseCallback = func() {
			//p("AppCloseCallback called. B.Swp.Recver.LastFrameClientConsumed=%v", B.Swp.Recver.LastFrameClientConsumed)
			close(senderClosed)
		}

		var n, ntot int64
		var expectedSeqNum int64
		for {
			//fmt.Printf("\n ... about to receive on B.ReadMessagesCh %p\n", B.ReadMessagesCh)
			select {
			case seq := <-B.ReadMessagesCh:
				//ns := len(seq.Seq)
				//fmt.Fprintf(os.Stderr, "\n B filetransfer_test testrec() got sequence len %v from B.ReadMessagesCh. SeqNum:[%v, %v]\n", ns, seq.Seq[0].SeqNum, seq.Seq[ns-1].SeqNum)
				for k, pk := range seq.Seq {
					if pk.SeqNum != expectedSeqNum {
						panic(fmt.Sprintf(
							"expected SeqNum %v, but got %v",
							expectedSeqNum, pk.SeqNum))
					}
					expectedSeqNum++
					// copy to dest, handling short writes only.
					var from int64
					for {
						n, err = io.Copy(dest, bytes.NewBuffer(pk.Data[from:]))
						_ = k
						//fmt.Fprintf(os.Stderr, "\n %v-th io.Copy gave n=%v, err=%v\n", k, n, err)
						ntot += n
						if err == io.ErrShortWrite {
							p("hanlding io.ErrShortWrite in copy loop")
							from += n
							continue
						} else {
							break
						}
					}
					panicOn(err)
					//fmt.Printf("\n")
					//fmt.Fprintf(os.Stderr, "\ndone with latest io.Copy, err was nil. n=%v, ntot=%v\n", n, ntot)
				}
			case <-B.Halt.Done.Chan:
				fmt.Printf("recv got B.Done\n")
				close(done)
				return

			case <-senderClosed:
				fmt.Printf("recv got senderClosed\n")
				close(done)
				return

				// ridiculous end-of-transfer indicator, but for debugging...
				//			case <-time.After(4 * time.Second):
				//				fmt.Printf("debug: recv loop timeout after 4 sec\n")
				//				close(done)
				//				return
			}
		}
	}
}

func SequentialPayload(n int64) []byte {
	if n%8 != 0 {
		panic(fmt.Sprintf("n == %v must be a multiple of 8; has remainder %v", n, n%8))
	}

	k := uint64(n / 8)
	by := make([]byte, n)
	j := uint64(0)
	for i := uint64(0); i < k; i++ {
		j = i * 8
		binary.LittleEndian.PutUint64(by[j:j+8], j)
	}
	return by
}

func nearestOctet(pos int, by []byte) (a, b, c int64) {
	n := len(by)
	pos -= (pos % 8)
	if pos-8 >= 0 && pos < n {
		a = int64(binary.LittleEndian.Uint64(by[pos-8 : pos]))
	}
	if pos >= 0 && pos+8 < n {
		b = int64(binary.LittleEndian.Uint64(by[pos : pos+8]))
	}
	if pos+8 >= 0 && pos+16 < n {
		c = int64(binary.LittleEndian.Uint64(by[pos+8 : pos+16]))
	}
	return a, b, c
}

func showSeq(by []byte, m int) {
	//fmt.Printf("showSeq called with len(by)=%v, m=%v\n", len(by), m)
	fmt.Printf("\n")
	n := len(by)
	if n%8 != 0 {
		panic(fmt.Sprintf("len(by) == n == %v must be a multiple of 8; has remainder %v", n, n%8))
	}
	for i := 0; i*8+8 <= n; i = i + m {
		j := i * 8
		//p("i = %v.  j=%v. m=%v. n=%v. len(by)=%v.  (i+8)*8+8=%v <= n(%v) is %v", i, j, m, n, len(by), (i+m)*8+8, n, (i+m)*8+8 <= n)
		a := int64(binary.LittleEndian.Uint64(by[j : j+8]))
		fmt.Printf("at %08d: %08d\n", j, a)
		if a != int64(j) {
			panic(fmt.Sprintf("detected j != a, at j=%v, a=%v", int64(j), a))
		}
	}
}

func Test041File(t *testing.T) {

	cv.Convey("SequentialPayload() produces a byte-numbered octet payload", t, func() {
		for i := 8; i < 128; i += 8 {
			by := SequentialPayload(int64(i))
			showSeq(by, 1)
		}
	})
}
<|endoftext|>


<commit_before>package fixchain

import (
	"net/http"
	"testing"

	"github.com/google/certificate-transparency/go/x509"
)

var constructChainTests = []fixTest{
	// constructChain()
	{ // Correct chain returns chain
		cert:  googleLeaf,
		chain: []string{thawteIntermediate, verisignRoot},
		roots: []string{verisignRoot},

		function: "constructChain",
		expectedChains: [][]string{
			{"Google", "Thawte", "VeriSign"},
		},
	},
	{
		cert:  testLeaf,
		chain: []string{testIntermediate2, testIntermediate1, testRoot},
		roots: []string{testRoot},

		function: "constructChain",
		expectedChains: [][]string{
			{"Leaf", "Intermediate2", "Intermediate1", "CA"},
			{"Leaf", "Intermediate2", "Intermediate1", "CA", "CA"},
		},
	},
	{ // No roots results in an error
		cert:  googleLeaf,
		chain: []string{thawteIntermediate, verisignRoot},

		function:     "constructChain",
		expectedErrs: []errorType{VerifyFailed},
	},
	{ // Incomplete chain results in an error
		cert:  googleLeaf,
		roots: []string{verisignRoot},

		function:     "constructChain",
		expectedErrs: []errorType{VerifyFailed},
	},
	{ // The wrong intermediate and root results in an error
		cert:  megaLeaf,
		chain: []string{thawteIntermediate, verisignRoot},
		roots: []string{verisignRoot},

		function:     "constructChain",
		expectedErrs: []errorType{VerifyFailed},
	},
	{ // The wrong root results in an error
		cert:  megaLeaf,
		chain: []string{comodoIntermediate, verisignRoot},
		roots: []string{verisignRoot},

		function:     "constructChain",
		expectedErrs: []errorType{VerifyFailed},
	},
}

var fixChainTests = []fixTest{
	// fixChain()
	{ // Correct chain returns chain
		cert:  googleLeaf,
		chain: []string{thawteIntermediate, verisignRoot},
		roots: []string{verisignRoot},

		function: "fixChain",
		expectedChains: [][]string{
			{"Google", "Thawte", "VeriSign"},
		},
	},
	{ // No roots results in an error
		cert:  googleLeaf,
		chain: []string{thawteIntermediate, verisignRoot},

		function:     "fixChain",
		expectedErrs: []errorType{FixFailed},
	},
	{ // No roots where chain that will be built contains a loop results in error
		cert:  testC,
		chain: []string{testB, testA},

		function:     "fixChain",
		expectedErrs: []errorType{FixFailed},
	},
	{ // Incomplete chain returns fixed chain
		cert:  googleLeaf,
		roots: []string{verisignRoot},

		function: "fixChain",
		expectedChains: [][]string{
			{"Google", "Thawte", "VeriSign"},
		},
	},
	{
		cert:  testLeaf,
		chain: []string{testIntermediate2},
		roots: []string{testRoot},

		function: "fixChain",
		expectedChains: [][]string{
			{"Leaf", "Intermediate2", "Intermediate1", "CA"},
		},
	},
	{
		cert:  testLeaf,
		chain: []string{testIntermediate1},
		roots: []string{testRoot},

		function: "fixChain",
		expectedChains: [][]string{
			{"Leaf", "Intermediate2", "Intermediate1", "CA"},
		},
	},
	{
		cert:  testLeaf,
		roots: []string{testRoot},

		function: "fixChain",
		expectedChains: [][]string{
			{"Leaf", "Intermediate2", "Intermediate1", "CA"},
		},
	},
	{ // The wrong intermediate and root results in an error
		cert:  megaLeaf,
		chain: []string{thawteIntermediate, verisignRoot},
		roots: []string{verisignRoot},

		function:     "fixChain",
		expectedErrs: []errorType{FixFailed},
	},
	{ // The wrong root results in an error
		cert:  megaLeaf,
		chain: []string{comodoIntermediate, verisignRoot},
		roots: []string{verisignRoot},

		function:     "fixChain",
		expectedErrs: []errorType{FixFailed},
	},
	// TODO(katjoyce): Add test where cert has multiple URLs in AIA extension.
}

func setUpFix(t *testing.T, i int, ft *fixTest) *toFix {
	// Create & populate toFix to test from fixTest info
	fix := &toFix{
		cert:  GetTestCertificateFromPEM(t, ft.cert),
		chain: newDedupedChain(extractTestChain(t, i, ft.chain)),
		roots: extractTestRoots(t, i, ft.roots),
		cache: newURLCache(&http.Client{Transport: &testRoundTripper{}}, false),
	}

	intermediates := x509.NewCertPool()
	for j, cert := range ft.chain {
		ok := intermediates.AppendCertsFromPEM([]byte(cert))
		if !ok {
			t.Errorf("#%d: Failed to parse intermediate #%d", i, j)
		}
	}

	fix.opts = &x509.VerifyOptions{
		Intermediates:     intermediates,
		Roots:             fix.roots,
		DisableTimeChecks: true,
		KeyUsages:         []x509.ExtKeyUsage{x509.ExtKeyUsageAny},
	}

	return fix
}

func testFixChainFunctions(t *testing.T, i int, ft *fixTest) {
	fix := setUpFix(t, i, ft)

	var chains [][]*x509.Certificate
	var ferrs []*FixError
	switch ft.function {
	case "constructChain":
		chains, ferrs = fix.constructChain()
	case "fixChain":
		chains, ferrs = fix.fixChain()
	case "handleChain":
		chains, ferrs = fix.handleChain()
	}

	matchTestChainList(t, i, ft.expectedChains, chains)
	matchTestErrorList(t, i, ft.expectedErrs, ferrs)
}

func TestFixChainFunctions(t *testing.T) {
	var allTests []fixTest
	allTests = append(allTests, constructChainTests...)
	allTests = append(allTests, fixChainTests...)
	allTests = append(allTests, handleChainTests...)
	for i, ft := range allTests {
		testFixChainFunctions(t, i, &ft)
	}
}

func TestFix(t *testing.T) {
	for i, test := range handleChainTests {
		chains, ferrs := Fix(GetTestCertificateFromPEM(t, test.cert),
			extractTestChain(t, i, test.chain),
			extractTestRoots(t, i, test.roots),
			&http.Client{Transport: &testRoundTripper{}})

		matchTestChainList(t, i, test.expectedChains, chains)
		matchTestErrorList(t, i, test.expectedErrs, ferrs)
	}
}
<commit_msg>[go/fixchain] updated x509 lib doesn't return duplicate roots<commit_after>package fixchain

import (
	"net/http"
	"testing"

	"github.com/google/certificate-transparency/go/x509"
)

var constructChainTests = []fixTest{
	// constructChain()
	{ // Correct chain returns chain
		cert:  googleLeaf,
		chain: []string{thawteIntermediate, verisignRoot},
		roots: []string{verisignRoot},

		function: "constructChain",
		expectedChains: [][]string{
			{"Google", "Thawte", "VeriSign"},
		},
	},
	{
		cert:  testLeaf,
		chain: []string{testIntermediate2, testIntermediate1, testRoot},
		roots: []string{testRoot},

		function: "constructChain",
		expectedChains: [][]string{
			{"Leaf", "Intermediate2", "Intermediate1", "CA"},
		},
	},
	{ // No roots results in an error
		cert:  googleLeaf,
		chain: []string{thawteIntermediate, verisignRoot},

		function:     "constructChain",
		expectedErrs: []errorType{VerifyFailed},
	},
	{ // Incomplete chain results in an error
		cert:  googleLeaf,
		roots: []string{verisignRoot},

		function:     "constructChain",
		expectedErrs: []errorType{VerifyFailed},
	},
	{ // The wrong intermediate and root results in an error
		cert:  megaLeaf,
		chain: []string{thawteIntermediate, verisignRoot},
		roots: []string{verisignRoot},

		function:     "constructChain",
		expectedErrs: []errorType{VerifyFailed},
	},
	{ // The wrong root results in an error
		cert:  megaLeaf,
		chain: []string{comodoIntermediate, verisignRoot},
		roots: []string{verisignRoot},

		function:     "constructChain",
		expectedErrs: []errorType{VerifyFailed},
	},
}

var fixChainTests = []fixTest{
	// fixChain()
	{ // Correct chain returns chain
		cert:  googleLeaf,
		chain: []string{thawteIntermediate, verisignRoot},
		roots: []string{verisignRoot},

		function: "fixChain",
		expectedChains: [][]string{
			{"Google", "Thawte", "VeriSign"},
		},
	},
	{ // No roots results in an error
		cert:  googleLeaf,
		chain: []string{thawteIntermediate, verisignRoot},

		function:     "fixChain",
		expectedErrs: []errorType{FixFailed},
	},
	{ // No roots where chain that will be built contains a loop results in error
		cert:  testC,
		chain: []string{testB, testA},

		function:     "fixChain",
		expectedErrs: []errorType{FixFailed},
	},
	{ // Incomplete chain returns fixed chain
		cert:  googleLeaf,
		roots: []string{verisignRoot},

		function: "fixChain",
		expectedChains: [][]string{
			{"Google", "Thawte", "VeriSign"},
		},
	},
	{
		cert:  testLeaf,
		chain: []string{testIntermediate2},
		roots: []string{testRoot},

		function: "fixChain",
		expectedChains: [][]string{
			{"Leaf", "Intermediate2", "Intermediate1", "CA"},
		},
	},
	{
		cert:  testLeaf,
		chain: []string{testIntermediate1},
		roots: []string{testRoot},

		function: "fixChain",
		expectedChains: [][]string{
			{"Leaf", "Intermediate2", "Intermediate1", "CA"},
		},
	},
	{
		cert:  testLeaf,
		roots: []string{testRoot},

		function: "fixChain",
		expectedChains: [][]string{
			{"Leaf", "Intermediate2", "Intermediate1", "CA"},
		},
	},
	{ // The wrong intermediate and root results in an error
		cert:  megaLeaf,
		chain: []string{thawteIntermediate, verisignRoot},
		roots: []string{verisignRoot},

		function:     "fixChain",
		expectedErrs: []errorType{FixFailed},
	},
	{ // The wrong root results in an error
		cert:  megaLeaf,
		chain: []string{comodoIntermediate, verisignRoot},
		roots: []string{verisignRoot},

		function:     "fixChain",
		expectedErrs: []errorType{FixFailed},
	},
	// TODO(katjoyce): Add test where cert has multiple URLs in AIA extension.
}

func setUpFix(t *testing.T, i int, ft *fixTest) *toFix {
	// Create & populate toFix to test from fixTest info
	fix := &toFix{
		cert:  GetTestCertificateFromPEM(t, ft.cert),
		chain: newDedupedChain(extractTestChain(t, i, ft.chain)),
		roots: extractTestRoots(t, i, ft.roots),
		cache: newURLCache(&http.Client{Transport: &testRoundTripper{}}, false),
	}

	intermediates := x509.NewCertPool()
	for j, cert := range ft.chain {
		ok := intermediates.AppendCertsFromPEM([]byte(cert))
		if !ok {
			t.Errorf("#%d: Failed to parse intermediate #%d", i, j)
		}
	}

	fix.opts = &x509.VerifyOptions{
		Intermediates:     intermediates,
		Roots:             fix.roots,
		DisableTimeChecks: true,
		KeyUsages:         []x509.ExtKeyUsage{x509.ExtKeyUsageAny},
	}

	return fix
}

func testFixChainFunctions(t *testing.T, i int, ft *fixTest) {
	fix := setUpFix(t, i, ft)

	var chains [][]*x509.Certificate
	var ferrs []*FixError
	switch ft.function {
	case "constructChain":
		chains, ferrs = fix.constructChain()
	case "fixChain":
		chains, ferrs = fix.fixChain()
	case "handleChain":
		chains, ferrs = fix.handleChain()
	}

	matchTestChainList(t, i, ft.expectedChains, chains)
	matchTestErrorList(t, i, ft.expectedErrs, ferrs)
}

func TestFixChainFunctions(t *testing.T) {
	var allTests []fixTest
	allTests = append(allTests, constructChainTests...)
	allTests = append(allTests, fixChainTests...)
	allTests = append(allTests, handleChainTests...)
	for i, ft := range allTests {
		testFixChainFunctions(t, i, &ft)
	}
}

func TestFix(t *testing.T) {
	for i, test := range handleChainTests {
		chains, ferrs := Fix(GetTestCertificateFromPEM(t, test.cert),
			extractTestChain(t, i, test.chain),
			extractTestRoots(t, i, test.roots),
			&http.Client{Transport: &testRoundTripper{}})

		matchTestChainList(t, i, test.expectedChains, chains)
		matchTestErrorList(t, i, test.expectedErrs, ferrs)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"net/http"

	"github.com/bborbe/portfolio/handler"
	"github.com/bborbe/log"
	"github.com/facebookgo/grace/gracehttp"
)

var (
	logger          = log.DefaultLogger
	addressPtr      = flag.String("a0", ":48568", "Zero address to bind to.")
	documentRootPtr = flag.String("root", "", "Document root directory")
	logLevelPtr     = flag.String("loglevel", log.INFO_STRING, "one of OFF,TRACE,DEBUG,INFO,WARN,ERROR")
)

func main() {
	defer logger.Close()
	flag.Parse()
	gracehttp.Serve(createServer(*addressPtr, *documentRootPtr))
}

func createServer(address string, documentRoot string) *http.Server {
	logger.SetLevelThreshold(log.LogStringToLevel(*logLevelPtr))
	logger.Debugf("set log level to %s", *logLevelPtr)
	return &http.Server{Addr: address, Handler: handler.NewHandler(documentRoot)}
}
<commit_msg>format<commit_after>package main

import (
	"flag"
	"net/http"

	"github.com/bborbe/log"
	"github.com/bborbe/portfolio/handler"
	"github.com/facebookgo/grace/gracehttp"
)

var (
	logger          = log.DefaultLogger
	addressPtr      = flag.String("a0", ":48568", "Zero address to bind to.")
	documentRootPtr = flag.String("root", "", "Document root directory")
	logLevelPtr     = flag.String("loglevel", log.INFO_STRING, "one of OFF,TRACE,DEBUG,INFO,WARN,ERROR")
)

func main() {
	defer logger.Close()
	flag.Parse()
	gracehttp.Serve(createServer(*addressPtr, *documentRootPtr))
}

func createServer(address string, documentRoot string) *http.Server {
	logger.SetLevelThreshold(log.LogStringToLevel(*logLevelPtr))
	logger.Debugf("set log level to %s", *logLevelPtr)
	return &http.Server{Addr: address, Handler: handler.NewHandler(documentRoot)}
}
<|endoftext|>