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

// CMAC message authentication code, defined in
// NIST Special Publication SP 800-38B.

package cmac

import (
	"crypto/cipher"
	"crypto/subtle"
	"errors"
	"hash"
)

const (
	// minimal irreducible polynomial of degree b
	r64  = 0x1b
	r128 = 0x87
)

type cmac struct {
	k1, k2, ci, digest []byte
	p                  int // position in ci
	c                  cipher.Block
}

// NewCMAC returns a new instance of a CMAC message authentication code
// digest using the given cipher.Block.
func NewCMAC(c cipher.Block) (hash.Hash, error) {
	var r int
	n := c.BlockSize()
	switch n {
	case 64 / 8:
		r = r64
	case 128 / 8:
		r = r128
	default:
		return nil, errors.New("NewCMAC: invalid cipher block size")
	}

	d := new(cmac)
	d.c = c
	d.k1 = make([]byte, n)
	d.k2 = make([]byte, n)
	d.ci = make([]byte, n)
	d.digest = make([]byte, n)

	// Subkey generation, p. 7
	c.Encrypt(d.k1, d.k1)

	x := subtle.ConstantTimeSelect(shift1(d.k1, d.k1), r, 0)
	d.k1[n-1] ^= byte(x)

	y := subtle.ConstantTimeSelect(shift1(d.k1, d.k2), r, 0)
	d.k2[n-1] ^= byte(y)

	return d, nil
}

// Reset clears the digest state, starting a new digest.
func (d *cmac) Reset() {
	for i := range d.ci {
		d.ci[i] = 0
	}
	d.p = 0
}

// Write adds the given data to the digest state.
func (d *cmac) Write(p []byte) (n int, err error) {
	// Xor input into ci.
	for _, c := range p {
		// If ci is full, encrypt and start over.
		if d.p >= len(d.ci) {
			d.c.Encrypt(d.ci, d.ci)
			d.p = 0
		}
		d.ci[d.p] ^= c
		d.p++
	}
	return len(p), nil
}

// Sum returns the CMAC digest, one cipher block in length,
// of the data written with Write.
func (d *cmac) Sum(in []byte) []byte {
	// Finish last block, mix in key, encrypt.
	// Don't edit ci, in case caller wants
	// to keep digesting after call to Sum.
	k := d.k1
	if d.p < len(d.digest) {
		k = d.k2
	}
	for i := 0; i < len(d.ci); i++ {
		d.digest[i] = d.ci[i] ^ k[i]
	}
	if d.p < len(d.digest) {
		d.digest[d.p] ^= 0x80
	}
	d.c.Encrypt(d.digest, d.digest)
	return append(in, d.digest...)
}

func (d *cmac) Size() int { return len(d.digest) }

func (d *cmac) BlockSize() int { return d.c.BlockSize() }

func shift1(src, dst []byte) int {
	var b byte
	for i := len(src) - 1; i >= 0; i-- {
		bb := src[i] >> 7
		dst[i] = src[i]<<1 | b
		b = bb
	}
	return int(b)
}
<commit_msg>Rearrange selection for clarity<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// CMAC message authentication code, defined in
// NIST Special Publication SP 800-38B.

package cmac

import (
	"crypto/cipher"
	"crypto/subtle"
	"errors"
	"hash"
)

const (
	// minimal irreducible polynomial of degree b
	r64  = 0x1b
	r128 = 0x87
)

type cmac struct {
	k1, k2, ci, digest []byte
	p                  int // position in ci
	c                  cipher.Block
}

// NewCMAC returns a new instance of a CMAC message authentication code
// digest using the given cipher.Block.
func NewCMAC(c cipher.Block) (hash.Hash, error) {
	var r int
	n := c.BlockSize()
	switch n {
	case 64 / 8:
		r = r64
	case 128 / 8:
		r = r128
	default:
		return nil, errors.New("NewCMAC: invalid cipher block size")
	}

	d := new(cmac)
	d.c = c
	d.k1 = make([]byte, n)
	d.k2 = make([]byte, n)
	d.ci = make([]byte, n)
	d.digest = make([]byte, n)

	// Subkey generation, p. 7
	c.Encrypt(d.k1, d.k1)

	v1 := shift1(d.k1, d.k1)
	d.k1[n-1] ^= byte(subtle.ConstantTimeSelect(v1, r, 0))

	v2 := shift1(d.k1, d.k2)
	d.k2[n-1] ^= byte(subtle.ConstantTimeSelect(v2, r, 0))

	return d, nil
}

// Reset clears the digest state, starting a new digest.
func (d *cmac) Reset() {
	for i := range d.ci {
		d.ci[i] = 0
	}
	d.p = 0
}

// Write adds the given data to the digest state.
func (d *cmac) Write(p []byte) (n int, err error) {
	// Xor input into ci.
	for _, c := range p {
		// If ci is full, encrypt and start over.
		if d.p >= len(d.ci) {
			d.c.Encrypt(d.ci, d.ci)
			d.p = 0
		}
		d.ci[d.p] ^= c
		d.p++
	}
	return len(p), nil
}

// Sum returns the CMAC digest, one cipher block in length,
// of the data written with Write.
func (d *cmac) Sum(in []byte) []byte {
	// Finish last block, mix in key, encrypt.
	// Don't edit ci, in case caller wants
	// to keep digesting after call to Sum.
	k := d.k1
	if d.p < len(d.digest) {
		k = d.k2
	}
	for i := 0; i < len(d.ci); i++ {
		d.digest[i] = d.ci[i] ^ k[i]
	}
	if d.p < len(d.digest) {
		d.digest[d.p] ^= 0x80
	}
	d.c.Encrypt(d.digest, d.digest)
	return append(in, d.digest...)
}

func (d *cmac) Size() int { return len(d.digest) }

func (d *cmac) BlockSize() int { return d.c.BlockSize() }

func shift1(src, dst []byte) int {
	var b byte
	for i := len(src) - 1; i >= 0; i-- {
		bb := src[i] >> 7
		dst[i] = src[i]<<1 | b
		b = bb
	}
	return int(b)
}
<|endoftext|>


<commit_before>// Copyright (c) 2015 The btcsuite developers
// Copyright (c) 2015-2016 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package blockchain

// TODO Make benchmarking tests for various functions, such as sidechain
// evaluation.
<commit_msg>blockchain: Add benchmark for ancestor traversal.<commit_after>// Copyright (c) 2019 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package blockchain

import (
	"testing"
)

// BenchmarkAncestor benchmarks ancestor traversal for various numbers of nodes.
func BenchmarkAncestor(b *testing.B) {
	// Construct a synthetic block chain with consisting of the following
	// structure.
	// 	0 -> 1 -> 2 -> ... -> 499997 -> 499998 -> 499999  -> 500000
	// 	                                      \-> 499999a
	// 	                            \-> 499998a
	branch0Nodes := chainedFakeNodes(nil, 500001)
	branch1Nodes := chainedFakeNodes(branch0Nodes[499998], 1)
	branch2Nodes := chainedFakeNodes(branch0Nodes[499997], 1)

	b.ReportAllocs()
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		branchTip(branch0Nodes).Ancestor(0)
		branchTip(branch0Nodes).Ancestor(131072) // Power of two.
		branchTip(branch0Nodes).Ancestor(131071) // One less than power of two.
		branchTip(branch0Nodes).Ancestor(131070) // Two less than power of two.
		branchTip(branch1Nodes).Ancestor(0)
		branchTip(branch2Nodes).Ancestor(0)
	}
}
<|endoftext|>


<commit_before>package v2

import (
	"fmt"
	"sync/atomic"

	"github.com/tendermint/tendermint/libs/log"
)

// TODO
// * revisit panic conditions
// * audit log levels
// * Convert routine to an interface with concrete implmentation

type handleFunc = func(event Event) (Events, error)

type Routine struct {
	name     string
	input    chan Event
	errors   chan error
	out      chan Event
	stopped  chan struct{}
	rdy      chan struct{}
	fin      chan error
	running  *uint32
	handle   handleFunc
	logger   log.Logger
	metrics  *Metrics
	stopping *uint32
}

func newRoutine(name string, handleFunc handleFunc) *Routine {
	return &Routine{
		name:     name,
		input:    make(chan Event, 1),
		handle:   handleFunc,
		errors:   make(chan error, 1),
		out:      make(chan Event, 1),
		stopped:  make(chan struct{}, 1),
		rdy:      make(chan struct{}, 1),
		fin:      make(chan error, 1),
		running:  new(uint32),
		stopping: new(uint32),
		logger:   log.NewNopLogger(),
		metrics:  NopMetrics(),
	}
}

func (rt *Routine) setLogger(logger log.Logger) {
	rt.logger = logger
}

func (rt *Routine) setMetrics(metrics *Metrics) {
	rt.metrics = metrics
}

func (rt *Routine) start() {
	rt.logger.Info(fmt.Sprintf("%s: run\n", rt.name))
	starting := atomic.CompareAndSwapUint32(rt.running, uint32(0), uint32(1))
	if !starting {
		panic("Routine has already started")
	}
	rt.rdy <- struct{}{}
	errorsDrained := false
	for {
		if !rt.isRunning() {
			rt.logger.Info(fmt.Sprintf("%s: breaking because not running\n", rt.name))
			break
		}
		select {
		case iEvent, ok := <-rt.input:
			rt.metrics.EventsIn.With("routine", rt.name).Add(1)
			if !ok {
				if !errorsDrained {
					rt.logger.Info(fmt.Sprintf("%s: waiting for errors to drain\n", rt.name))

					continue // wait for errors to be drainned
				}
				rt.logger.Info(fmt.Sprintf("%s: stopping\n", rt.name))
				rt.stopped <- struct{}{}
				rt.terminate(fmt.Errorf("stopped"))
				return
			}
			oEvents, err := rt.handle(iEvent)
			rt.metrics.EventsHandled.With("routine", rt.name).Add(1)
			if err != nil {
				rt.terminate(err)
				return
			}
			rt.metrics.EventsOut.With("routine", rt.name).Add(float64(len(oEvents)))
			rt.logger.Info(fmt.Sprintf("%s handled %d events\n", rt.name, len(oEvents)))
			for _, event := range oEvents {
				rt.logger.Info(fmt.Sprintln("writting back to output"))
				rt.out <- event
			}
		case iEvent, ok := <-rt.errors:
			rt.metrics.ErrorsIn.With("routine", rt.name).Add(1)
			if !ok {
				rt.logger.Info(fmt.Sprintf("%s: errors closed\n", rt.name))
				errorsDrained = true
				continue
			}
			oEvents, err := rt.handle(iEvent)
			rt.metrics.ErrorsHandled.With("routine", rt.name).Add(1)
			if err != nil {
				rt.terminate(err)
				return
			}
			rt.metrics.ErrorsOut.With("routine", rt.name).Add(float64(len(oEvents)))
			for _, event := range oEvents {
				rt.out <- event
			}
		}
	}
}
func (rt *Routine) feedback() {
	for event := range rt.out {
		rt.trySend(event)
	}
}

func (rt *Routine) trySend(event Event) bool {
	if !rt.isRunning() || rt.isStopping() {
		return false
	}

	rt.logger.Info(fmt.Sprintf("%s: sending %+v", rt.name, event))
	if err, ok := event.(error); ok {
		select {
		case rt.errors <- err:
			rt.metrics.ErrorsSent.With("routine", rt.name).Add(1)
			return true
		default:
			rt.metrics.ErrorsShed.With("routine", rt.name).Add(1)
			rt.logger.Info(fmt.Sprintf("%s: errors channel was full\n", rt.name))
			return false
		}
	} else {
		select {
		case rt.input <- event:
			rt.metrics.EventsSent.With("routine", rt.name).Add(1)
			return true
		default:
			rt.metrics.EventsShed.With("routine", rt.name).Add(1)
			rt.logger.Info(fmt.Sprintf("%s: channel was full\n", rt.name))
			return false
		}
	}
}

func (rt *Routine) isRunning() bool {
	return atomic.LoadUint32(rt.running) == 1
}

func (rt *Routine) isStopping() bool {
	return atomic.LoadUint32(rt.stopping) == 1
}

func (rt *Routine) ready() chan struct{} {
	return rt.rdy
}

func (rt *Routine) next() chan Event {
	return rt.out
}

func (rt *Routine) stop() {
	if !rt.isRunning() {
		return
	}

	rt.logger.Info(fmt.Sprintf("%s: stop\n", rt.name))
	stopping := atomic.CompareAndSwapUint32(rt.stopping, uint32(0), uint32(1))
	if !stopping {
		panic("Routine has already stopped")
	}

	close(rt.input)
	close(rt.errors)
	<-rt.stopped
}

func (rt *Routine) final() chan error {
	return rt.fin
}

func (rt *Routine) terminate(reason error) {
	stopped := atomic.CompareAndSwapUint32(rt.running, uint32(1), uint32(0))
	if !stopped {
		panic("called stop but already stopped")
	}
	rt.fin <- reason
}
<commit_msg>typo fix<commit_after>package v2

import (
	"fmt"
	"sync/atomic"

	"github.com/tendermint/tendermint/libs/log"
)

// TODO
// * revisit panic conditions
// * audit log levels
// * Convert routine to an interface with concrete implmentation

type handleFunc = func(event Event) (Events, error)

type Routine struct {
	name     string
	input    chan Event
	errors   chan error
	out      chan Event
	stopped  chan struct{}
	rdy      chan struct{}
	fin      chan error
	running  *uint32
	handle   handleFunc
	logger   log.Logger
	metrics  *Metrics
	stopping *uint32
}

func newRoutine(name string, handleFunc handleFunc) *Routine {
	return &Routine{
		name:     name,
		input:    make(chan Event, 1),
		handle:   handleFunc,
		errors:   make(chan error, 1),
		out:      make(chan Event, 1),
		stopped:  make(chan struct{}, 1),
		rdy:      make(chan struct{}, 1),
		fin:      make(chan error, 1),
		running:  new(uint32),
		stopping: new(uint32),
		logger:   log.NewNopLogger(),
		metrics:  NopMetrics(),
	}
}

func (rt *Routine) setLogger(logger log.Logger) {
	rt.logger = logger
}

func (rt *Routine) setMetrics(metrics *Metrics) {
	rt.metrics = metrics
}

func (rt *Routine) start() {
	rt.logger.Info(fmt.Sprintf("%s: run\n", rt.name))
	starting := atomic.CompareAndSwapUint32(rt.running, uint32(0), uint32(1))
	if !starting {
		panic("Routine has already started")
	}
	rt.rdy <- struct{}{}
	errorsDrained := false
	for {
		if !rt.isRunning() {
			rt.logger.Info(fmt.Sprintf("%s: breaking because not running\n", rt.name))
			break
		}
		select {
		case iEvent, ok := <-rt.input:
			rt.metrics.EventsIn.With("routine", rt.name).Add(1)
			if !ok {
				if !errorsDrained {
					rt.logger.Info(fmt.Sprintf("%s: waiting for errors to drain\n", rt.name))

					continue // wait for errors to be drainned
				}
				rt.logger.Info(fmt.Sprintf("%s: stopping\n", rt.name))
				rt.stopped <- struct{}{}
				rt.terminate(fmt.Errorf("stopped"))
				return
			}
			oEvents, err := rt.handle(iEvent)
			rt.metrics.EventsHandled.With("routine", rt.name).Add(1)
			if err != nil {
				rt.terminate(err)
				return
			}
			rt.metrics.EventsOut.With("routine", rt.name).Add(float64(len(oEvents)))
			rt.logger.Info(fmt.Sprintf("%s handled %d events\n", rt.name, len(oEvents)))
			for _, event := range oEvents {
				rt.logger.Info(fmt.Sprintln("writing back to output"))
				rt.out <- event
			}
		case iEvent, ok := <-rt.errors:
			rt.metrics.ErrorsIn.With("routine", rt.name).Add(1)
			if !ok {
				rt.logger.Info(fmt.Sprintf("%s: errors closed\n", rt.name))
				errorsDrained = true
				continue
			}
			oEvents, err := rt.handle(iEvent)
			rt.metrics.ErrorsHandled.With("routine", rt.name).Add(1)
			if err != nil {
				rt.terminate(err)
				return
			}
			rt.metrics.ErrorsOut.With("routine", rt.name).Add(float64(len(oEvents)))
			for _, event := range oEvents {
				rt.out <- event
			}
		}
	}
}
func (rt *Routine) feedback() {
	for event := range rt.out {
		rt.trySend(event)
	}
}

func (rt *Routine) trySend(event Event) bool {
	if !rt.isRunning() || rt.isStopping() {
		return false
	}

	rt.logger.Info(fmt.Sprintf("%s: sending %+v", rt.name, event))
	if err, ok := event.(error); ok {
		select {
		case rt.errors <- err:
			rt.metrics.ErrorsSent.With("routine", rt.name).Add(1)
			return true
		default:
			rt.metrics.ErrorsShed.With("routine", rt.name).Add(1)
			rt.logger.Info(fmt.Sprintf("%s: errors channel was full\n", rt.name))
			return false
		}
	} else {
		select {
		case rt.input <- event:
			rt.metrics.EventsSent.With("routine", rt.name).Add(1)
			return true
		default:
			rt.metrics.EventsShed.With("routine", rt.name).Add(1)
			rt.logger.Info(fmt.Sprintf("%s: channel was full\n", rt.name))
			return false
		}
	}
}

func (rt *Routine) isRunning() bool {
	return atomic.LoadUint32(rt.running) == 1
}

func (rt *Routine) isStopping() bool {
	return atomic.LoadUint32(rt.stopping) == 1
}

func (rt *Routine) ready() chan struct{} {
	return rt.rdy
}

func (rt *Routine) next() chan Event {
	return rt.out
}

func (rt *Routine) stop() {
	if !rt.isRunning() {
		return
	}

	rt.logger.Info(fmt.Sprintf("%s: stop\n", rt.name))
	stopping := atomic.CompareAndSwapUint32(rt.stopping, uint32(0), uint32(1))
	if !stopping {
		panic("Routine has already stopped")
	}

	close(rt.input)
	close(rt.errors)
	<-rt.stopped
}

func (rt *Routine) final() chan error {
	return rt.fin
}

func (rt *Routine) terminate(reason error) {
	stopped := atomic.CompareAndSwapUint32(rt.running, uint32(1), uint32(0))
	if !stopped {
		panic("called stop but already stopped")
	}
	rt.fin <- reason
}
<|endoftext|>


<commit_before>package baseftrwapp

import (
	"encoding/json"
	"fmt"
	"net/http"

	"compress/gzip"

	"io"

	"github.com/Financial-Times/neo-utils-go/neoutils"
	"github.com/Financial-Times/up-rw-app-api-go/rwapi"
	log "github.com/Sirupsen/logrus"
	"github.com/gorilla/mux"
)

type httpHandlers struct {
	s rwapi.Service
}

func (hh *httpHandlers) putHandler(w http.ResponseWriter, req *http.Request) {
	vars := mux.Vars(req)
	uuid := vars["uuid"]

	w.Header().Add("Content-Type", "application/json")

	var body io.Reader = req.Body
	if req.Header.Get("Content-Encoding") == "gzip" {
		unzipped, err := gzip.NewReader(req.Body)
		if err != nil {
			writeJSONError(w, err.Error(), http.StatusBadRequest)
			return
		}
		defer unzipped.Close()
		body = unzipped
	}

	dec := json.NewDecoder(body)
	inst, docUUID, err := hh.s.DecodeJSON(dec)

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

	if docUUID != uuid {
		writeJSONError(w, fmt.Sprintf("uuid does not match: '%v' '%v'", docUUID, uuid), http.StatusBadRequest)
		return
	}

	err = hh.s.Write(inst)

	if err != nil {
		switch e := err.(type) {
		case noContentReturnedError:
			writeJSONError(w, e.NoContentReturnedDetails(), http.StatusNoContent)
			return
		case *neoutils.ConstraintViolationError:
			writeJSONError(w, e.Error(), http.StatusConflict)
			return
		case invalidRequestError:
			writeJSONError(w, e.InvalidRequestDetails(), http.StatusBadRequest)
			return
		default:
			writeJSONError(w, err.Error(), http.StatusServiceUnavailable)
			return
		}
	}
	//Not necessary for a 200 to be returned, but for PUT requests, if don't specify, don't see 200 status logged in request logs
	w.WriteHeader(http.StatusOK)
}

func (hh *httpHandlers) deleteHandler(w http.ResponseWriter, req *http.Request) {
	vars := mux.Vars(req)
	uuid := vars["uuid"]

	deleted, err := hh.s.Delete(uuid)

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

	if deleted {
		w.WriteHeader(http.StatusNoContent)
	} else {
		w.WriteHeader(http.StatusNotFound)
	}
}

func (hh *httpHandlers) getHandler(w http.ResponseWriter, req *http.Request) {
	vars := mux.Vars(req)
	uuid := vars["uuid"]

	obj, found, err := hh.s.Read(uuid)

	w.Header().Add("Content-Type", "application/json")

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

	if !found {
		w.WriteHeader(http.StatusNotFound)
		return
	}

	enc := json.NewEncoder(w)
	if err := enc.Encode(obj); err != nil {
		writeJSONError(w, err.Error(), http.StatusInternalServerError)
		return
	}
}

func (hh *httpHandlers) countHandler(w http.ResponseWriter, r *http.Request) {

	count, err := hh.s.Count()

	w.Header().Add("Content-Type", "application/json")

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

	enc := json.NewEncoder(w)

	if err := enc.Encode(count); err != nil {
		writeJSONError(w, err.Error(), http.StatusServiceUnavailable)
		return
	}
}

func (hh *httpHandlers) idsHandler(w http.ResponseWriter, r *http.Request) {

	idService, ok := hh.s.(rwapi.IDService)
	if !ok {
		w.WriteHeader(http.StatusNotImplemented)
		return
	}

	ids := make(chan rwapi.IDEntry, 4096)
	errs := make(chan error)

	stop := make(chan struct{})
	defer close(stop)

	go func() {
		idService.IDs(ids, errs, stop)
		close(ids)
	}()

	w.Header().Add("Content-Type", "application/json")

	enc := json.NewEncoder(w)

	var err error
	for err == nil {
		select {
		case id, ok := <-ids:
			if !ok {
				return
			}
			err = enc.Encode(id)
		case err = <-errs:
		}
	}

	log.Errorf(err.Error())

	// at this point, the best we can do is close the connection to inform
	// the client of the error, because we've already said "200"
	conn, _, err := w.(http.Hijacker).Hijack()
	if err != nil {
		// there is very little we can do here. Since we're in an http
		// handler, panic is okay. It will be recovered from and will
		// not crash the application, but at least we will capture the
		// cause.
		log.Panicf(err.Error())
	}
	conn.Close()
	return
}

func pingHandler(w http.ResponseWriter, req *http.Request) {
	fmt.Fprintf(w, "pong")
}

// buildInfoHandler - This is a stop gap and will be added to when we can define what we should display here
func buildInfoHandler(w http.ResponseWriter, req *http.Request) {
	fmt.Fprintf(w, "build-info")
}

func writeJSONError(w http.ResponseWriter, errorMsg string, statusCode int) {
	w.WriteHeader(statusCode)
	fmt.Fprintln(w, fmt.Sprintf("{\"message\": \"%s\"}", errorMsg))
}
<commit_msg>Updated to use new simpler IDs API<commit_after>package baseftrwapp

import (
	"encoding/json"
	"fmt"
	"net/http"

	"compress/gzip"

	"io"

	"github.com/Financial-Times/neo-utils-go/neoutils"
	"github.com/Financial-Times/up-rw-app-api-go/rwapi"
	log "github.com/Sirupsen/logrus"
	"github.com/gorilla/mux"
)

type httpHandlers struct {
	s rwapi.Service
}

func (hh *httpHandlers) putHandler(w http.ResponseWriter, req *http.Request) {
	vars := mux.Vars(req)
	uuid := vars["uuid"]

	w.Header().Add("Content-Type", "application/json")

	var body io.Reader = req.Body
	if req.Header.Get("Content-Encoding") == "gzip" {
		unzipped, err := gzip.NewReader(req.Body)
		if err != nil {
			writeJSONError(w, err.Error(), http.StatusBadRequest)
			return
		}
		defer unzipped.Close()
		body = unzipped
	}

	dec := json.NewDecoder(body)
	inst, docUUID, err := hh.s.DecodeJSON(dec)

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

	if docUUID != uuid {
		writeJSONError(w, fmt.Sprintf("uuid does not match: '%v' '%v'", docUUID, uuid), http.StatusBadRequest)
		return
	}

	err = hh.s.Write(inst)

	if err != nil {
		switch e := err.(type) {
		case noContentReturnedError:
			writeJSONError(w, e.NoContentReturnedDetails(), http.StatusNoContent)
			return
		case *neoutils.ConstraintViolationError:
			writeJSONError(w, e.Error(), http.StatusConflict)
			return
		case invalidRequestError:
			writeJSONError(w, e.InvalidRequestDetails(), http.StatusBadRequest)
			return
		default:
			writeJSONError(w, err.Error(), http.StatusServiceUnavailable)
			return
		}
	}
	//Not necessary for a 200 to be returned, but for PUT requests, if don't specify, don't see 200 status logged in request logs
	w.WriteHeader(http.StatusOK)
}

func (hh *httpHandlers) deleteHandler(w http.ResponseWriter, req *http.Request) {
	vars := mux.Vars(req)
	uuid := vars["uuid"]

	deleted, err := hh.s.Delete(uuid)

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

	if deleted {
		w.WriteHeader(http.StatusNoContent)
	} else {
		w.WriteHeader(http.StatusNotFound)
	}
}

func (hh *httpHandlers) getHandler(w http.ResponseWriter, req *http.Request) {
	vars := mux.Vars(req)
	uuid := vars["uuid"]

	obj, found, err := hh.s.Read(uuid)

	w.Header().Add("Content-Type", "application/json")

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

	if !found {
		w.WriteHeader(http.StatusNotFound)
		return
	}

	enc := json.NewEncoder(w)
	if err := enc.Encode(obj); err != nil {
		writeJSONError(w, err.Error(), http.StatusInternalServerError)
		return
	}
}

func (hh *httpHandlers) countHandler(w http.ResponseWriter, r *http.Request) {

	count, err := hh.s.Count()

	w.Header().Add("Content-Type", "application/json")

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

	enc := json.NewEncoder(w)

	if err := enc.Encode(count); err != nil {
		writeJSONError(w, err.Error(), http.StatusServiceUnavailable)
		return
	}
}

func (hh *httpHandlers) idsHandler(w http.ResponseWriter, r *http.Request) {

	idService, ok := hh.s.(rwapi.IDService)
	if !ok {
		w.WriteHeader(http.StatusNotImplemented)
		return
	}

	w.Header().Add("Content-Type", "application/json")

	enc := json.NewEncoder(w)

	err := idService.IDs(func(id rwapi.IDEntry) (bool, error) {
		if err := enc.Encode(id); err != nil {
			return false, err
		}
		return true, nil
	})

	if err != nil {
		log.Errorf(err.Error())

		// at this point, the best we can do is close the connection to inform
		// the client of the error, because we've already said "200"
		conn, _, err := w.(http.Hijacker).Hijack()
		if err != nil {
			// there is very little we can do here. Since we're in an http
			// handler, panic is okay. It will be recovered from and will
			// not crash the application, but at least we will capture the
			// cause.
			log.Panicf(err.Error())
		}
		conn.Close()
	}

	return
}

func pingHandler(w http.ResponseWriter, req *http.Request) {
	fmt.Fprintf(w, "pong")
}

// buildInfoHandler - This is a stop gap and will be added to when we can define what we should display here
func buildInfoHandler(w http.ResponseWriter, req *http.Request) {
	fmt.Fprintf(w, "build-info")
}

func writeJSONError(w http.ResponseWriter, errorMsg string, statusCode int) {
	w.WriteHeader(statusCode)
	fmt.Fprintln(w, fmt.Sprintf("{\"message\": \"%s\"}", errorMsg))
}
<|endoftext|>


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

package main

import (
	"github.com/gorilla/websocket"
	"log"
	"net/http"
	"time"
	"encoding/json"
	"fmt"
)

// connection is an middleman between the websocket connection and the hub.
// There is 1 socket connection for each chat member. Each connection
// is associated with 1 hub. When the user writes a message to the socket
// connection, the message is passed to the hub for broadcast.
// When the connection receives a message from the hub, it is written to the user.
type connection struct {

	chatroomId string

	hub *hub

	// The websocket connection.
	ws *websocket.Conn

	// Buffered channel of outbound messages.
	send chan []byte
}

const (
	// Time allowed to write a message to the peer.
	writeWait = 10 * time.Second

	// Time allowed to read the next pong message from the peer.
	pongWait = 60 * time.Second

	// Send pings to peer with this period. Must be less than pongWait.
	pingPeriod = (pongWait * 9) / 10

	// Maximum message size allowed from peer.
	maxMessageSize = 4096
)

var upgrader = websocket.Upgrader{
	ReadBufferSize:  4096,
	WriteBufferSize: 4096,
}

/* Converts to JSON */
func parseMessage(data map[string]string) []byte {

	/* Convert nicknameId to encryptedNickname */
	if data["msgType"] == "newMessage"{

		nicknameId := data["nicknameId"]
		var encryptedNickname string
		err := db.QueryRow("SELECT encrypted_nickname FROM nicknames WHERE id= ?", nicknameId).Scan(&encryptedNickname)
		if err != nil {
			fmt.Println("No nickname found with id: " + nicknameId)
			encryptedNickname = "Unknown"
		}
		delete(data, "nicknameId")
		data["encryptedNickname"] = encryptedNickname

	} else if data["msgType"] == "newMember"{
		//
	} else if data["msgType"] == "keyExchangeReq"{
		//
	} else if data["msgType"] == "keyExchangeResp"{
		//
	} else {
		fmt.Println("Unknown Message Type")
	}

	json, err := json.Marshal(data)
	if err != nil {
		fmt.Println(err.Error())
		json = []byte("Error")
	}

	return json
}

// readPump pumps messages from the websocket connection to the hub. (User sending msg)
func (c *connection) readPump() {
	defer func() {
		c.hub.unregister <- c
		c.ws.Close()
	}()
	c.ws.SetReadLimit(maxMessageSize)
	c.ws.SetReadDeadline(time.Now().Add(pongWait))
	c.ws.SetPongHandler(func(string) error { c.ws.SetReadDeadline(time.Now().Add(pongWait)); return nil })
	for {
		_, bytes, err := c.ws.ReadMessage()
		if err != nil {
			break
		}

		var data map[string]string

		err = json.Unmarshal(bytes, &data);
		if err != nil{
			fmt.Println(err.Error())
			break
		}

		c.hub.broadcast <- parseMessage(data)
	}
}

// write writes a message with the given message type and payload.
func (c *connection) write(mt int, payload []byte) error {
	c.ws.SetWriteDeadline(time.Now().Add(writeWait))
	return c.ws.WriteMessage(mt, payload)
}

// writePump pumps messages from the hub to the websocket connection. (User receiving msg)
func (c *connection) writePump() {
	ticker := time.NewTicker(pingPeriod)
	defer func() {
		ticker.Stop()
		c.ws.Close()
	}()
	for {
		select {
		case message, ok := <-c.send:
			if !ok {
				c.write(websocket.CloseMessage, []byte{})
				return
			}
			if err := c.write(websocket.TextMessage, message); err != nil {
				return
			}
		case <-ticker.C:
			if err := c.write(websocket.PingMessage, []byte{}); err != nil {
				return
			}
		}
	}
}

// initiates websocket requests from the peer.
func serveWs(w http.ResponseWriter, r *http.Request) {
	if r.Method != "GET" {
		http.Error(w, "Method not allowed", 405)
		return
	}

	chatroomId := r.FormValue("chatroomId")

	ws, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Println(err)
		return
	}

	h := chatIdToHub[chatroomId]
	c := &connection{chatroomId: chatroomId, hub: h, send: make(chan []byte, 256), ws: ws}
	c.hub.register <- c
	go c.writePump()
	c.readPump()
}
<commit_msg>allow all origins (ios/android clients)<commit_after>// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"github.com/gorilla/websocket"
	"log"
	"net/http"
	"time"
	"encoding/json"
	"fmt"
)

// connection is an middleman between the websocket connection and the hub.
// There is 1 socket connection for each chat member. Each connection
// is associated with 1 hub. When the user writes a message to the socket
// connection, the message is passed to the hub for broadcast.
// When the connection receives a message from the hub, it is written to the user.
type connection struct {

	chatroomId string

	hub *hub

	// The websocket connection.
	ws *websocket.Conn

	// Buffered channel of outbound messages.
	send chan []byte
}

const (
	// Time allowed to write a message to the peer.
	writeWait = 10 * time.Second

	// Time allowed to read the next pong message from the peer.
	pongWait = 60 * time.Second

	// Send pings to peer with this period. Must be less than pongWait.
	pingPeriod = (pongWait * 9) / 10

	// Maximum message size allowed from peer.
	maxMessageSize = 4096
)

var upgrader = websocket.Upgrader{
	ReadBufferSize:  4096,
	WriteBufferSize: 4096,
}

/* Converts to JSON */
func parseMessage(data map[string]string) []byte {

	/* Convert nicknameId to encryptedNickname */
	if data["msgType"] == "newMessage"{

		nicknameId := data["nicknameId"]
		var encryptedNickname string
		err := db.QueryRow("SELECT encrypted_nickname FROM nicknames WHERE id= ?", nicknameId).Scan(&encryptedNickname)
		if err != nil {
			fmt.Println("No nickname found with id: " + nicknameId)
			encryptedNickname = "Unknown"
		}
		delete(data, "nicknameId")
		data["encryptedNickname"] = encryptedNickname

	} else if data["msgType"] == "newMember"{
		//
	} else if data["msgType"] == "keyExchangeReq"{
		//
	} else if data["msgType"] == "keyExchangeResp"{
		//
	} else {
		fmt.Println("Unknown Message Type")
	}

	json, err := json.Marshal(data)
	if err != nil {
		fmt.Println(err.Error())
		json = []byte("Error")
	}

	return json
}

// readPump pumps messages from the websocket connection to the hub. (User sending msg)
func (c *connection) readPump() {
	defer func() {
		c.hub.unregister <- c
		c.ws.Close()
	}()
	c.ws.SetReadLimit(maxMessageSize)
	c.ws.SetReadDeadline(time.Now().Add(pongWait))
	c.ws.SetPongHandler(func(string) error { c.ws.SetReadDeadline(time.Now().Add(pongWait)); return nil })
	for {
		_, bytes, err := c.ws.ReadMessage()
		if err != nil {
			break
		}

		var data map[string]string

		err = json.Unmarshal(bytes, &data);
		if err != nil{
			fmt.Println(err.Error())
			break
		}

		c.hub.broadcast <- parseMessage(data)
	}
}

// write writes a message with the given message type and payload.
func (c *connection) write(mt int, payload []byte) error {
	c.ws.SetWriteDeadline(time.Now().Add(writeWait))
	return c.ws.WriteMessage(mt, payload)
}

// writePump pumps messages from the hub to the websocket connection. (User receiving msg)
func (c *connection) writePump() {
	ticker := time.NewTicker(pingPeriod)
	defer func() {
		ticker.Stop()
		c.ws.Close()
	}()
	for {
		select {
		case message, ok := <-c.send:
			if !ok {
				c.write(websocket.CloseMessage, []byte{})
				return
			}
			if err := c.write(websocket.TextMessage, message); err != nil {
				return
			}
		case <-ticker.C:
			if err := c.write(websocket.PingMessage, []byte{}); err != nil {
				return
			}
		}
	}
}

// initiates websocket requests from the peer.
func serveWs(w http.ResponseWriter, r *http.Request) {
	if r.Method != "GET" {
		http.Error(w, "Method not allowed", 405)
		return
	}

	chatroomId := r.FormValue("chatroomId")

	var upgrader = websocket.Upgrader{
	   CheckOrigin: func(r *http.Request) bool { return true },
	}

	ws, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Println(err)
		return
	}

	h := chatIdToHub[chatroomId]
	c := &connection{chatroomId: chatroomId, hub: h, send: make(chan []byte, 256), ws: ws}
	c.hub.register <- c
	go c.writePump()
	c.readPump()
}
<|endoftext|>


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

// This package provides LDAP client functions.
package ldap

import (
	"crypto/tls"
	"errors"
	"fmt"
	"github.com/mavricknz/asn1-ber"
	"net"
	"os"
	"sync"
	"time"
)

// Conn - LDAP Connection and also pre/post connect configuation
//	IsTLS bool // default false
//	IsSSL bool // default false
//	Debug bool // default false
//	NetworkConnectTimeout time.Duration // default 0 no timeout
//	ReadTimeout    time.Duration // default 0 no timeout
//	AbandonMessageOnReadTimeout bool // send abandon on a ReadTimeout (not for searches yet)
//	Network        string // default empty "tcp"
//	Addr           string // default empty
//
// A minimal connection...
//	ldap := NewLDAPConnection("localhost",389)
//  err := ldap.Connect() // returns the same conn passed but connected.
type LDAPConnection struct {
	IsTLS bool
	IsSSL bool
	Debug bool

	Addr                        string
	NetworkConnectTimeout       time.Duration
	ReadTimeout                 time.Duration
	AbandonMessageOnReadTimeout bool

	TlsConfig *tls.Config

	conn               net.Conn
	chanResults        map[uint64]chan *ber.Packet
	lockChanResults    sync.RWMutex
	chanProcessMessage chan *messagePacket
	closeLock          sync.RWMutex
	chanMessageID      chan uint64
	connected          bool
}

// Connect connects using information in LDAPConnection.
// LDAPConnection should be populated with connection information.
func (l *LDAPConnection) Connect() *Error {
	l.chanResults = map[uint64]chan *ber.Packet{}
	l.chanProcessMessage = make(chan *messagePacket)
	l.chanMessageID = make(chan uint64)

	if l.conn == nil {
		var c net.Conn
		var err error
		if l.NetworkConnectTimeout > 0 {
			c, err = net.DialTimeout("tcp", l.Addr, l.NetworkConnectTimeout)
		} else {
			c, err = net.Dial("tcp", l.Addr)
		}

		if err != nil {
			return NewError(ErrorNetwork, err)
		}

		if l.IsSSL {
			tlsConn := tls.Client(c, l.TlsConfig)
			err = tlsConn.Handshake()
			if err != nil {
				return NewError(ErrorNetwork, err)
			}
			l.conn = tlsConn
		} else {
			l.conn = c
		}
	}
	l.start()
	l.connected = true
	if l.IsTLS {
		err := l.startTLS()
		if err != nil {
			return NewError(ErrorNetwork, err)
		}
	}
	return nil
}

// NewConn returns a new basic connection. Should start connection via
// Connect
func NewLDAPConnection(server string, port uint16) *LDAPConnection {
	return &LDAPConnection{
		Addr: fmt.Sprintf("%s:%d", server, port),
	}
}

func (l *LDAPConnection) start() {
	go l.reader()
	go l.processMessages()
}

// Close closes the connection.
func (l *LDAPConnection) Close() *Error {
	if l.Debug {
		fmt.Println("Starting Close().")
	}
	l.sendProcessMessage(&messagePacket{Op: MessageQuit})
	return nil
}

// Returns the next available messageID
func (l *LDAPConnection) nextMessageID() (messageID uint64, ok bool) {
	messageID, ok = <-l.chanMessageID
	if l.Debug {
		fmt.Printf("MessageID: %d, ok: %v\n", messageID, ok)
	}
	return
}

// StartTLS sends the command to start a TLS session and then creates a new TLS Client
func (l *LDAPConnection) startTLS() *Error {
	messageID, ok := l.nextMessageID()
	if !ok {
		return NewError(ErrorClosing, errors.New("MessageID channel is closed."))
	}

	if l.IsSSL {
		return NewError(ErrorNetwork, errors.New("Already encrypted"))
	}

	tlsRequest := encodeTLSRequest()
	packet, err := requestBuildPacket(messageID, tlsRequest, nil)

	if err != nil {
		return err
	}

	err = l.sendReqRespPacket(messageID, packet)
	if err != nil {
		return err
	}

	conn := tls.Client(l.conn, nil)
	stderr := conn.Handshake()
	if stderr != nil {
		return NewError(ErrorNetwork, stderr)
	}
	l.IsSSL = true
	l.conn = conn

	return nil
}

func encodeTLSRequest() (tlsRequest *ber.Packet) {
	tlsRequest = ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationExtendedRequest, nil, "Start TLS")
	tlsRequest.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimative, 0, "1.3.6.1.4.1.1466.20037", "TLS Extended Command"))
	return
}

const (
	MessageQuit     = 0
	MessageRequest  = 1
	MessageResponse = 2
	MessageFinish   = 3
)

type messagePacket struct {
	Op        int
	MessageID uint64
	Packet    *ber.Packet
	Channel   chan *ber.Packet
}

func (l *LDAPConnection) getNewResultChannel(message_id uint64) (out chan *ber.Packet, err *Error) {
	// as soon as a channel is requested add to chanResults to never miss
	// on cleanup.
	l.lockChanResults.Lock()
	defer l.lockChanResults.Unlock()

	if l.chanResults == nil {
		return nil, NewError(ErrorClosing, errors.New("Conenction closing/closed"))
	}

	if _, ok := l.chanResults[message_id]; ok {
		errStr := fmt.Sprintf("chanResults already allocated, message_id: %d", message_id)
		return nil, NewError(ErrorUnknown, errors.New(errStr))
	}

	out = make(chan *ber.Packet, ResultChanBufferSize)
	l.chanResults[message_id] = out
	return
}

func (l *LDAPConnection) sendMessage(p *ber.Packet) (out chan *ber.Packet, err *Error) {
	message_id := p.Children[0].Value.(uint64)
	// sendProcessMessage may not process a message on shutdown
	// getNewResultChannel adds id/chan to chan results
	out, err = l.getNewResultChannel(message_id)
	if err != nil {
		return
	}
	if l.Debug {
		fmt.Printf("sendMessage-> message_id: %d, out: %v\n", message_id, out)
	}

	message_packet := &messagePacket{Op: MessageRequest, MessageID: message_id, Packet: p, Channel: out}
	l.sendProcessMessage(message_packet)
	return
}

func (l *LDAPConnection) processMessages() {
	defer l.closeAllChannels()
	defer func() {
		// Close all channels, connection and quit.
		// Use closeLock to stop MessageRequests
		// and l.connected to stop any future MessageRequests.
		l.closeLock.Lock()
		defer l.closeLock.Unlock()
		l.connected = false
		// will shutdown reader.
		l.conn.Close()
	}()
	var message_id uint64 = 1
	var message_packet *messagePacket

	for {
		select {
		case l.chanMessageID <- message_id:
			message_id++
		case message_packet = <-l.chanProcessMessage:
			switch message_packet.Op {
			case MessageQuit:
				if l.Debug {
					fmt.Printf("Shutting down\n")
				}
				return
			case MessageRequest:
				// Add to message list and write to network
				if l.Debug {
					fmt.Printf("Sending message %d\n", message_packet.MessageID)
				}
				buf := message_packet.Packet.Bytes()
				for len(buf) > 0 {
					n, err := l.conn.Write(buf)
					if err != nil {
						if l.Debug {
							fmt.Printf("Error Sending Message: %s\n", err.Error())
						}
						return
					}
					if n == len(buf) {
						break
					}
					buf = buf[n:]
				}
			case MessageFinish:
				// Remove from message list
				if l.Debug {
					fmt.Printf("Finished message %d\n", message_packet.MessageID)
				}
				l.lockChanResults.Lock()
				delete(l.chanResults, message_packet.MessageID)
				l.lockChanResults.Unlock()
			}
		}
	}
}

func (l *LDAPConnection) closeAllChannels() {
	l.lockChanResults.Lock()
	defer l.lockChanResults.Unlock()
	for MessageID, Channel := range l.chanResults {
		if l.Debug {
			fmt.Printf("Closing channel for MessageID %d\n", MessageID)
		}
		close(Channel)
		delete(l.chanResults, MessageID)
	}
	l.chanResults = nil

	close(l.chanMessageID)
	l.chanMessageID = nil

	close(l.chanProcessMessage)
	l.chanProcessMessage = nil
}

func (l *LDAPConnection) finishMessage(MessageID uint64) {
	message_packet := &messagePacket{Op: MessageFinish, MessageID: MessageID}
	l.sendProcessMessage(message_packet)
}

func (l *LDAPConnection) reader() {
	defer l.Close()
	for {
		p, err := ber.ReadPacket(l.conn)
		if err != nil {
			if l.Debug {
				fmt.Printf("ldap.reader: %s\n", err.Error())
			}
			return
		}

		addLDAPDescriptions(p)

		message_id := p.Children[0].Value.(uint64)
		message_packet := &messagePacket{Op: MessageResponse, MessageID: message_id, Packet: p}

		l.readerToChanResults(message_packet)
	}
}

func (l *LDAPConnection) readerToChanResults(message_packet *messagePacket) {
	defer func() {
		if r := recover(); r != nil {
			fmt.Fprintln(os.Stderr, "Recovered in readerToChanResults", r)
		}
	}()
	if l.Debug {
		fmt.Printf("Receiving message %d\n", message_packet.MessageID)
	}

	// very small chance on disconnect to write to a closed channel as
	// lockChanResults is unlocked immediately hence defer above.
	// Don't lock while sending to chanResult below as that can block and hold
	// the lock.
	l.lockChanResults.RLock()
	chanResult, ok := l.chanResults[message_packet.MessageID]
	l.lockChanResults.RUnlock()

	if !ok {
		if l.Debug {
			fmt.Printf("Message Result chan not found (possible Abandon), MessageID: %d\n", message_packet.MessageID)
		}
	} else {
		// chanResult is a buffered channel of ResultChanBufferSize
		chanResult <- message_packet.Packet
	}
}

func (l *LDAPConnection) sendProcessMessage(message *messagePacket) {
	go func() {
		// multiple senders can queue on l.chanProcessMessage
		// but block on shutdown.
		l.closeLock.RLock()
		defer l.closeLock.RUnlock()
		if l.connected {
			l.chanProcessMessage <- message
		}
	}()
}
<commit_msg>changed errors to the std error interface.<commit_after>// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This package provides LDAP client functions.
package ldap

import (
	"crypto/tls"
	"fmt"
	"github.com/mavricknz/asn1-ber"
	"net"
	"os"
	"sync"
	"time"
)

// Conn - LDAP Connection and also pre/post connect configuation
//	IsTLS bool // default false
//	IsSSL bool // default false
//	Debug bool // default false
//	NetworkConnectTimeout time.Duration // default 0 no timeout
//	ReadTimeout    time.Duration // default 0 no timeout
//	AbandonMessageOnReadTimeout bool // send abandon on a ReadTimeout (not for searches yet)
//	Network        string // default empty "tcp"
//	Addr           string // default empty
//
// A minimal connection...
//	ldap := NewLDAPConnection("localhost",389)
//  err := ldap.Connect() // returns the same conn passed but connected.
type LDAPConnection struct {
	IsTLS bool
	IsSSL bool
	Debug bool

	Addr                        string
	NetworkConnectTimeout       time.Duration
	ReadTimeout                 time.Duration
	AbandonMessageOnReadTimeout bool

	TlsConfig *tls.Config

	conn               net.Conn
	chanResults        map[uint64]chan *ber.Packet
	lockChanResults    sync.RWMutex
	chanProcessMessage chan *messagePacket
	closeLock          sync.RWMutex
	chanMessageID      chan uint64
	connected          bool
}

// Connect connects using information in LDAPConnection.
// LDAPConnection should be populated with connection information.
func (l *LDAPConnection) Connect() error {
	l.chanResults = map[uint64]chan *ber.Packet{}
	l.chanProcessMessage = make(chan *messagePacket)
	l.chanMessageID = make(chan uint64)

	if l.conn == nil {
		var c net.Conn
		var err error
		if l.NetworkConnectTimeout > 0 {
			c, err = net.DialTimeout("tcp", l.Addr, l.NetworkConnectTimeout)
		} else {
			c, err = net.Dial("tcp", l.Addr)
		}

		if err != nil {
			return err
		}

		if l.IsSSL {
			tlsConn := tls.Client(c, l.TlsConfig)
			err = tlsConn.Handshake()
			if err != nil {
				return err
			}
			l.conn = tlsConn
		} else {
			l.conn = c
		}
	}
	l.start()
	l.connected = true
	if l.IsTLS {
		err := l.startTLS()
		if err != nil {
			return err
		}
	}
	return nil
}

// NewConn returns a new basic connection. Should start connection via
// Connect
func NewLDAPConnection(server string, port uint16) *LDAPConnection {
	return &LDAPConnection{
		Addr: fmt.Sprintf("%s:%d", server, port),
	}
}

func (l *LDAPConnection) start() {
	go l.reader()
	go l.processMessages()
}

// Close closes the connection.
func (l *LDAPConnection) Close() error {
	if l.Debug {
		fmt.Println("Starting Close().")
	}
	l.sendProcessMessage(&messagePacket{Op: MessageQuit})
	return nil
}

// Returns the next available messageID
func (l *LDAPConnection) nextMessageID() (messageID uint64, ok bool) {
	messageID, ok = <-l.chanMessageID
	if l.Debug {
		fmt.Printf("MessageID: %d, ok: %v\n", messageID, ok)
	}
	return
}

// StartTLS sends the command to start a TLS session and then creates a new TLS Client
func (l *LDAPConnection) startTLS() error {
	messageID, ok := l.nextMessageID()
	if !ok {
		return NewLDAPError(ErrorClosing, "MessageID channel is closed.")
	}

	if l.IsSSL {
		return NewLDAPError(ErrorNetwork, "Already encrypted")
	}

	tlsRequest := encodeTLSRequest()
	packet, err := requestBuildPacket(messageID, tlsRequest, nil)

	if err != nil {
		return err
	}

	err = l.sendReqRespPacket(messageID, packet)
	if err != nil {
		return err
	}

	conn := tls.Client(l.conn, nil)
	err = conn.Handshake()
	if err != nil {
		return err
	}
	l.IsSSL = true
	l.conn = conn

	return nil
}

func encodeTLSRequest() (tlsRequest *ber.Packet) {
	tlsRequest = ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationExtendedRequest, nil, "Start TLS")
	tlsRequest.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimative, 0, "1.3.6.1.4.1.1466.20037", "TLS Extended Command"))
	return
}

const (
	MessageQuit     = 0
	MessageRequest  = 1
	MessageResponse = 2
	MessageFinish   = 3
)

type messagePacket struct {
	Op        int
	MessageID uint64
	Packet    *ber.Packet
	Channel   chan *ber.Packet
}

func (l *LDAPConnection) getNewResultChannel(message_id uint64) (out chan *ber.Packet, err error) {
	// as soon as a channel is requested add to chanResults to never miss
	// on cleanup.
	l.lockChanResults.Lock()
	defer l.lockChanResults.Unlock()

	if l.chanResults == nil {
		return nil, NewLDAPError(ErrorClosing, "Connection closing/closed")
	}

	if _, ok := l.chanResults[message_id]; ok {
		errStr := fmt.Sprintf("chanResults already allocated, message_id: %d", message_id)
		return nil, NewLDAPError(ErrorUnknown, errStr)
	}

	out = make(chan *ber.Packet, ResultChanBufferSize)
	l.chanResults[message_id] = out
	return
}

func (l *LDAPConnection) sendMessage(p *ber.Packet) (out chan *ber.Packet, err error) {
	message_id := p.Children[0].Value.(uint64)
	// sendProcessMessage may not process a message on shutdown
	// getNewResultChannel adds id/chan to chan results
	out, err = l.getNewResultChannel(message_id)
	if err != nil {
		return
	}
	if l.Debug {
		fmt.Printf("sendMessage-> message_id: %d, out: %v\n", message_id, out)
	}

	message_packet := &messagePacket{Op: MessageRequest, MessageID: message_id, Packet: p, Channel: out}
	l.sendProcessMessage(message_packet)
	return
}

func (l *LDAPConnection) processMessages() {
	defer l.closeAllChannels()
	defer func() {
		// Close all channels, connection and quit.
		// Use closeLock to stop MessageRequests
		// and l.connected to stop any future MessageRequests.
		l.closeLock.Lock()
		defer l.closeLock.Unlock()
		l.connected = false
		// will shutdown reader.
		l.conn.Close()
	}()
	var message_id uint64 = 1
	var message_packet *messagePacket

	for {
		select {
		case l.chanMessageID <- message_id:
			message_id++
		case message_packet = <-l.chanProcessMessage:
			switch message_packet.Op {
			case MessageQuit:
				if l.Debug {
					fmt.Printf("Shutting down\n")
				}
				return
			case MessageRequest:
				// Add to message list and write to network
				if l.Debug {
					fmt.Printf("Sending message %d\n", message_packet.MessageID)
				}
				buf := message_packet.Packet.Bytes()
				for len(buf) > 0 {
					n, err := l.conn.Write(buf)
					if err != nil {
						if l.Debug {
							fmt.Printf("Error Sending Message: %s\n", err)
						}
						return
					}
					if n == len(buf) {
						break
					}
					buf = buf[n:]
				}
			case MessageFinish:
				// Remove from message list
				if l.Debug {
					fmt.Printf("Finished message %d\n", message_packet.MessageID)
				}
				l.lockChanResults.Lock()
				delete(l.chanResults, message_packet.MessageID)
				l.lockChanResults.Unlock()
			}
		}
	}
}

func (l *LDAPConnection) closeAllChannels() {
	l.lockChanResults.Lock()
	defer l.lockChanResults.Unlock()
	for MessageID, Channel := range l.chanResults {
		if l.Debug {
			fmt.Printf("Closing channel for MessageID %d\n", MessageID)
		}
		close(Channel)
		delete(l.chanResults, MessageID)
	}
	l.chanResults = nil

	close(l.chanMessageID)
	l.chanMessageID = nil

	close(l.chanProcessMessage)
	l.chanProcessMessage = nil
}

func (l *LDAPConnection) finishMessage(MessageID uint64) {
	message_packet := &messagePacket{Op: MessageFinish, MessageID: MessageID}
	l.sendProcessMessage(message_packet)
}

func (l *LDAPConnection) reader() {
	defer l.Close()
	for {
		p, err := ber.ReadPacket(l.conn)
		if err != nil {
			if l.Debug {
				fmt.Printf("ldap.reader: %s\n", err)
			}
			return
		}

		addLDAPDescriptions(p)

		message_id := p.Children[0].Value.(uint64)
		message_packet := &messagePacket{Op: MessageResponse, MessageID: message_id, Packet: p}

		l.readerToChanResults(message_packet)
	}
}

func (l *LDAPConnection) readerToChanResults(message_packet *messagePacket) {
	defer func() {
		if r := recover(); r != nil {
			fmt.Fprintln(os.Stderr, "Recovered in readerToChanResults", r)
		}
	}()
	if l.Debug {
		fmt.Printf("Receiving message %d\n", message_packet.MessageID)
	}

	// very small chance on disconnect to write to a closed channel as
	// lockChanResults is unlocked immediately hence defer above.
	// Don't lock while sending to chanResult below as that can block and hold
	// the lock.
	l.lockChanResults.RLock()
	chanResult, ok := l.chanResults[message_packet.MessageID]
	l.lockChanResults.RUnlock()

	if !ok {
		if l.Debug {
			fmt.Printf("Message Result chan not found (possible Abandon), MessageID: %d\n", message_packet.MessageID)
		}
	} else {
		// chanResult is a buffered channel of ResultChanBufferSize
		chanResult <- message_packet.Packet
	}
}

func (l *LDAPConnection) sendProcessMessage(message *messagePacket) {
	go func() {
		// multiple senders can queue on l.chanProcessMessage
		// but block on shutdown.
		l.closeLock.RLock()
		defer l.closeLock.RUnlock()
		if l.connected {
			l.chanProcessMessage <- message
		}
	}()
}
<|endoftext|>


<commit_before>package wemdigo

import (
	"sync"
	"time"

	"github.com/gorilla/websocket"
)

// Link instances wrap a Gorilla websocket and provkeye a link to
// a specific Mkeydle instance.  The Link is responsible for keeping
// the underlying websocket connection alive as well as reading / writing
// messages.
type Conn struct {
	ws        *websocket.Conn // hkeye
	wsConf    *WSConfig
	wgSend    sync.WaitGroup
	wgRec     sync.WaitGroup
	key       string
	deps      []string
	hubs      []string
	targets   []string
	unregSent bool
	// Conn owned channels.
	read chan *Message
	send chan *Message // Messages to write to the websocket.
	done chan struct{} // Terminates the main loop.
	err  chan struct{} // Weboscket + Middle error channel.
	// Middle instance channels shared by all connections.
	mid   chan *Message // Channel instance uses to speak to the Middle.
	unreg chan *Conn    // Middle's unregistration channel.
}

func (c *Conn) Init(cc ConnConfig, mid chan *Message, unreg chan *Conn) {
	c.ws = cc.Conn
	if cc.WSConf == nil {
		cc.WSConf = new(WSConfig)
		cc.WSConf.init()
	}
	c.key = cc.Key
	c.hubs = cc.Hubs
	c.targets = cc.Targets
	c.deps = cc.Deps
	c.wsConf = cc.WSConf
	c.mid = mid
	c.unreg = unreg
}

// NewConn to be initialized further by a Middle instance.
func NewConn() *Conn {
	return &Conn{
		err:  make(chan struct{}),
		read: make(chan *Message),
		send: make(chan *Message),
		done: make(chan struct{}),
	}
}

// Key returns the connection's key keyentifier and a bool indicating
// whether this value is set.  If the boolean is false, then this
// connection is not indirectly targetable.
func (c Conn) Key() (string, bool) {
	return c.key, c.key != ""
}

// HasKey reports whether the underlying connection is targetable.
func (c Conn) HasKey() bool {
	_, ok := c.Key()
	return ok
}

// Targets the connection subscribes to.
func (c *Conn) Targets() []string { return c.targets }

// Hugs the target subscribes to.
func (c *Conn) Hubs() []string { return c.hubs }

// Deps are target connections on which the instance depends.
func (c *Conn) Deps() []string { return c.deps }

// UnderlyingConn returns the underlying Gorilla websocket connection.
func (c Conn) UnderlyingConn() *websocket.Conn { return c.ws }

func (c *Conn) setReadDeadline() {
	var t time.Time
	if c.wsConf.PongWait != 0 {
		t = time.Now().Add(c.wsConf.PongWait)
	}
	c.ws.SetReadDeadline(t)
}

func (c *Conn) write(messageType int, data []byte) error {
	c.ws.SetWriteDeadline(time.Now().Add(c.wsConf.WriteWait))
	return c.ws.WriteMessage(messageType, data)
}

// readLoop pumps messages from the websocket Link to the Mkeydle.
func (c *Conn) readLoop() {
	defer func() {
		dlog("Conn %s sending to unregister chan.", c.key)
		c.ws.Close()
		close(c.read)

		// Wait until all sent messages have been evaluated by the handler
		// before unregistering with the Middle, as we do not want the
		// connection's dependencies to close before having a chance to write
		// all relevant messages.
		c.wgSend.Wait()
		c.err <- struct{}{}
	}()

	ponghandler := func(appData string) error {
		c.setReadDeadline()
		dlog("Conn %s saw a pong.", c.key)
		return nil
	}

	c.ws.SetPongHandler(ponghandler)

	for {
		mt, data, err := c.ws.ReadMessage()
		if err != nil {
			return
		}
		dlog("Conn %s read a message", c.key)
		msg := &Message{Type: mt, Data: data, origin: c}
		c.read <- msg
	}
}

// writeLoop is responsible for writing to the peer.  This is the only
// location where writing occurs.
func (c *Conn) writeLoop() {

	defer func() {
		c.write(websocket.CloseMessage, nil)
		c.ws.Close()
		dlog("Conn %s no longer writing messages.", c.key)
	}()

	for msg := range c.send {
		if err := c.write(msg.Type, msg.Data); err != nil {
			return
		}
	}
}

// main loop handles all communication with the Mkeydle layer.  Messages
// read by the underlying websocket and those to be written by it
// are first funneled through here.
func (c *Conn) mainLoop() {
	pinger := time.NewTicker(c.wsConf.PingPeriod)
	defer func() {
		c.ws.Close()
		pinger.Stop()
		close(c.send)
	}()

	for {
		select {
		case msg, ok := <-c.read:
			if ok {
				c.mid <- msg
			}
		case <-pinger.C:
			msg := &Message{Type: websocket.PingMessage, Data: nil}
			c.send <- msg
		case <-c.err:
			// Websocket can no longer read.
			if !c.unregSent {
				c.unregSent = true
				c.unreg <- c
			}
		case <-c.done:
			dlog("Conn %s received on done channel.", c.key)
			return
		}
	}
}

func (c *Conn) run() {
	go c.writeLoop()
	go c.readLoop()
	go c.mainLoop()
}
<commit_msg>Move debug statement.<commit_after>package wemdigo

import (
	"sync"
	"time"

	"github.com/gorilla/websocket"
)

// Link instances wrap a Gorilla websocket and provkeye a link to
// a specific Mkeydle instance.  The Link is responsible for keeping
// the underlying websocket connection alive as well as reading / writing
// messages.
type Conn struct {
	ws        *websocket.Conn // hkeye
	wsConf    *WSConfig
	wgSend    sync.WaitGroup
	wgRec     sync.WaitGroup
	key       string
	deps      []string
	hubs      []string
	targets   []string
	unregSent bool
	// Conn owned channels.
	read chan *Message
	send chan *Message // Messages to write to the websocket.
	done chan struct{} // Terminates the main loop.
	err  chan struct{} // Weboscket + Middle error channel.
	// Middle instance channels shared by all connections.
	mid   chan *Message // Channel instance uses to speak to the Middle.
	unreg chan *Conn    // Middle's unregistration channel.
}

func (c *Conn) Init(cc ConnConfig, mid chan *Message, unreg chan *Conn) {
	c.ws = cc.Conn
	if cc.WSConf == nil {
		cc.WSConf = new(WSConfig)
		cc.WSConf.init()
	}
	c.key = cc.Key
	c.hubs = cc.Hubs
	c.targets = cc.Targets
	c.deps = cc.Deps
	c.wsConf = cc.WSConf
	c.mid = mid
	c.unreg = unreg
}

// NewConn to be initialized further by a Middle instance.
func NewConn() *Conn {
	return &Conn{
		err:  make(chan struct{}),
		read: make(chan *Message),
		send: make(chan *Message),
		done: make(chan struct{}),
	}
}

// Key returns the connection's key keyentifier and a bool indicating
// whether this value is set.  If the boolean is false, then this
// connection is not indirectly targetable.
func (c Conn) Key() (string, bool) {
	return c.key, c.key != ""
}

// HasKey reports whether the underlying connection is targetable.
func (c Conn) HasKey() bool {
	_, ok := c.Key()
	return ok
}

// Targets the connection subscribes to.
func (c *Conn) Targets() []string { return c.targets }

// Hugs the target subscribes to.
func (c *Conn) Hubs() []string { return c.hubs }

// Deps are target connections on which the instance depends.
func (c *Conn) Deps() []string { return c.deps }

// UnderlyingConn returns the underlying Gorilla websocket connection.
func (c Conn) UnderlyingConn() *websocket.Conn { return c.ws }

func (c *Conn) setReadDeadline() {
	var t time.Time
	if c.wsConf.PongWait != 0 {
		t = time.Now().Add(c.wsConf.PongWait)
	}
	c.ws.SetReadDeadline(t)
}

func (c *Conn) write(messageType int, data []byte) error {
	c.ws.SetWriteDeadline(time.Now().Add(c.wsConf.WriteWait))
	return c.ws.WriteMessage(messageType, data)
}

// readLoop pumps messages from the websocket Link to the Mkeydle.
func (c *Conn) readLoop() {
	defer func() {
		c.ws.Close()
		close(c.read)

		// Wait until all sent messages have been evaluated by the handler
		// before unregistering with the Middle, as we do not want the
		// connection's dependencies to close before having a chance to write
		// all relevant messages.
		c.wgSend.Wait()
		c.err <- struct{}{}
	}()

	ponghandler := func(appData string) error {
		c.setReadDeadline()
		dlog("Conn %s saw a pong.", c.key)
		return nil
	}

	c.ws.SetPongHandler(ponghandler)

	for {
		mt, data, err := c.ws.ReadMessage()
		if err != nil {
			return
		}
		dlog("Conn %s read a message", c.key)
		msg := &Message{Type: mt, Data: data, origin: c}
		c.read <- msg
	}
}

// writeLoop is responsible for writing to the peer.  This is the only
// location where writing occurs.
func (c *Conn) writeLoop() {

	defer func() {
		c.write(websocket.CloseMessage, nil)
		c.ws.Close()
		dlog("Conn %s no longer writing messages.", c.key)
	}()

	for msg := range c.send {
		if err := c.write(msg.Type, msg.Data); err != nil {
			return
		}
	}
}

// main loop handles all communication with the Mkeydle layer.  Messages
// read by the underlying websocket and those to be written by it
// are first funneled through here.
func (c *Conn) mainLoop() {
	pinger := time.NewTicker(c.wsConf.PingPeriod)
	defer func() {
		c.ws.Close()
		pinger.Stop()
		close(c.send)
	}()

	for {
		select {
		case msg, ok := <-c.read:
			if ok {
				c.mid <- msg
			}
		case <-pinger.C:
			msg := &Message{Type: websocket.PingMessage, Data: nil}
			c.send <- msg
		case <-c.err:
			// Websocket can no longer read.
			if !c.unregSent {
				dlog("Conn %s sending to unregister chan.", c.key)
				c.unregSent = true
				c.unreg <- c
			}
		case <-c.done:
			dlog("Conn %s received on done channel.", c.key)
			return
		}
	}
}

func (c *Conn) run() {
	go c.writeLoop()
	go c.readLoop()
	go c.mainLoop()
}
<|endoftext|>


<commit_before>/*
Package raphanus - simple implementation of Redis-like in-memory cache
*/
package raphanus

import (
	"errors"
	"sync"
)

// MaxStringValueLength - string value max length
const MaxStringValueLength = 1024 * 1024 // 1 MB

// Common errors
var (
	ErrKeyNotExists     = errors.New("Key not exists")
	ErrKeyTypeMissmatch = errors.New("The type does not match")
	ErrListOutOfRange   = errors.New("List index is out of range")
)

type value struct {
	val interface{}
	ttl int
}

// DB - in-memory cache object
type DB struct {
	data     map[string]value
	withLock bool // execute get/set methods under lock
	*sync.RWMutex
}

// New - get new cache object
func New() DB {
	return DB{
		data:     map[string]value{},
		withLock: true,
		RWMutex:  new(sync.RWMutex),
	}
}

// UnderRLock - execute few read-methods undef one RLock
func (db *DB) UnderRLock(fn func()) {
	db.RLock()
	db.withLock = false
	fn()
	db.RUnlock()
	db.withLock = true
}

// UnderLock - execute few RW-methods undef one Lock
func (db *DB) UnderLock(fn func()) {
	db.Lock()
	db.withLock = false
	fn()
	db.Unlock()
	db.withLock = true
}

// Remove - remove key from cache
func (db *DB) Remove(key string) (err error) {
	if db.withLock {
		db.Lock()
		defer db.Unlock()
	}

	_, ok := db.data[key]
	if !ok {
		return ErrKeyNotExists
	}

	delete(db.data, key)
	return nil
}

// Keys - get all keys from cache (as []string)
func (db *DB) Keys() []string {
	if db.withLock {
		db.RLock()
		defer db.RUnlock()
	}

	result := make([]string, 0, len(db.data))
	for key := range db.data {
		result = append(result, key)
	}

	return result
}

// Len - return length of cache
func (db *DB) Len() int {
	return len(db.data)
}
<commit_msg>ttl is time<commit_after>/*
Package raphanus - simple implementation of Redis-like in-memory cache
*/
package raphanus

import (
	"errors"
	"sync"
	"time"
)

// MaxStringValueLength - string value max length
const MaxStringValueLength = 1024 * 1024 // 1 MB

// Common errors
var (
	ErrKeyNotExists     = errors.New("Key not exists")
	ErrKeyTypeMissmatch = errors.New("The type does not match")
	ErrListOutOfRange   = errors.New("List index is out of range")
)

type value struct {
	val interface{}
	ttl time.Time
}

// DB - in-memory cache object
type DB struct {
	data     map[string]value
	withLock bool // execute get/set methods under lock
	*sync.RWMutex
}

// New - get new cache object
func New() DB {
	return DB{
		data:     map[string]value{},
		withLock: true,
		RWMutex:  new(sync.RWMutex),
	}
}

// UnderRLock - execute few read-methods undef one RLock
func (db *DB) UnderRLock(fn func()) {
	db.RLock()
	db.withLock = false
	fn()
	db.RUnlock()
	db.withLock = true
}

// UnderLock - execute few RW-methods undef one Lock
func (db *DB) UnderLock(fn func()) {
	db.Lock()
	db.withLock = false
	fn()
	db.Unlock()
	db.withLock = true
}

// Remove - remove key from cache
func (db *DB) Remove(key string) (err error) {
	if db.withLock {
		db.Lock()
		defer db.Unlock()
	}

	_, ok := db.data[key]
	if !ok {
		return ErrKeyNotExists
	}

	delete(db.data, key)
	return nil
}

// Keys - get all keys from cache (as []string)
func (db *DB) Keys() []string {
	if db.withLock {
		db.RLock()
		defer db.RUnlock()
	}

	result := make([]string, 0, len(db.data))
	for key := range db.data {
		result = append(result, key)
	}

	return result
}

// Len - return length of cache
func (db *DB) Len() int {
	return len(db.data)
}
<|endoftext|>


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

// Package cors provides handlers to enable CORS support.
package cors

import (
	"net/http"
	"regexp"
	"strconv"
	"strings"
	"time"
)

const (
	headerAllowOrigin      = "Access-Control-Allow-Origin"
	headerAllowCredentials = "Access-Control-Allow-Credentials"
	headerAllowHeaders     = "Access-Control-Allow-Headers"
	headerAllowMethods     = "Access-Control-Allow-Methods"
	headerExposeHeaders    = "Access-Control-Expose-Headers"
	headerMaxAge           = "Access-Control-Max-Age"

	headerOrigin         = "Origin"
	headerRequestMethod  = "Access-Control-Request-Method"
	headerRequestHeaders = "Access-Control-Request-Headers"
)

var defaultAllowHeaders = []string{"Origin", "Accept", "Content-Type", "Authorization"}

// Represents Access Control options.
type Options struct {
	// If set, all origins are allowed.
	AllowAllOrigins bool
	// A list of allowed domain patterns.
	AllowOrigins []string
	// If set, allows to share auth credentials such as cookies.
	AllowCredentials bool
	// A list of allowed HTTP methods.
	AllowMethods []string
	// A list of allowed HTTP headers.
	AllowHeaders []string
	// A list of exposed HTTP headers.
	ExposeHeaders []string
	// Max age of the CORS headers.
	MaxAge time.Duration
}

// Converts options into CORS headers.
func (o *Options) Header(origin string) (headers map[string]string) {
	headers = make(map[string]string)
	// if origin is not alowed, don't extend the headers
	// with CORS headers.
	if !o.AllowAllOrigins && !o.IsOriginAllowed(origin) {
		return
	}

	// add allow origin
	if o.AllowAllOrigins {
		headers[headerAllowOrigin] = "*"
	} else {
		headers[headerAllowOrigin] = origin
	}

	// add allow credentials
	headers[headerAllowCredentials] = strconv.FormatBool(o.AllowCredentials)

	// add allow methods
	if len(o.AllowMethods) > 0 {
		headers[headerAllowMethods] = strings.Join(o.AllowMethods, ",")
	}

	// add allow headers
	if len(o.AllowHeaders) > 0 {
		// TODO: Add default headers
		headers[headerAllowHeaders] = strings.Join(o.AllowHeaders, ",")
	}

	// add exposed header
	if len(o.ExposeHeaders) > 0 {
		headers[headerExposeHeaders] = strings.Join(o.ExposeHeaders, ",")
	}
	// add a max age header
	if o.MaxAge > time.Duration(0) {
		headers[headerMaxAge] = strconv.FormatInt(int64(o.MaxAge/time.Second), 10)
	}
	return
}

// Converts options into CORS headers for a preflight response.
func (o *Options) PreflightHeader(origin, rMethod, rHeaders string) (headers map[string]string) {
	headers = make(map[string]string)
	if !o.AllowAllOrigins && !o.IsOriginAllowed(origin) {
		return
	}
	// verify if requested method is allowed
	// TODO: Too many for loops
	for _, method := range o.AllowMethods {
		if method == rMethod {
			headers[headerAllowMethods] = strings.Join(o.AllowMethods, ",")
			break
		}
	}

	// verify if requested headers are allowed
	var allowed []string
	for _, rHeader := range strings.Split(rHeaders, ",") {
		rHeader = strings.TrimSpace(rHeader)
	lookupLoop:
		for _, allowedHeader := range o.AllowHeaders {
			if strings.ToLower(rHeader) == strings.ToLower(allowedHeader) {
				allowed = append(allowed, rHeader)
				break lookupLoop
			}
		}
	}

	// add allow origin
	if o.AllowAllOrigins {
		headers[headerAllowOrigin] = "*"
	} else {
		headers[headerAllowOrigin] = origin
	}

	// add allowed headers
	if len(allowed) > 0 {
		headers[headerAllowHeaders] = strings.Join(allowed, ",")
	}

	// add exposed headers
	if len(o.ExposeHeaders) > 0 {
		headers[headerExposeHeaders] = strings.Join(o.ExposeHeaders, ",")
	}
	// add a max age header
	if o.MaxAge > time.Duration(0) {
		headers[headerMaxAge] = strconv.FormatInt(int64(o.MaxAge/time.Second), 10)
	}
	return
}

// Looks up if the origin matches one of the patterns
// provided in Options.AllowOrigins patterns.
func (o *Options) IsOriginAllowed(origin string) (allowed bool) {
	for _, pattern := range o.AllowOrigins {
		allowed, _ = regexp.MatchString(pattern, origin)
		if allowed {
			return
		}
	}
	return
}

// Allows CORS for requests those match the provided options.
func Allow(opts *Options) http.HandlerFunc {
	// Allow default headers if nothing is specified.
	if len(opts.AllowHeaders) == 0 {
		opts.AllowHeaders = defaultAllowHeaders
	}
	// Normalize regular expressions.
	for i, pattern := range opts.AllowOrigins {
		pattern = regexp.QuoteMeta(pattern)
		pattern = strings.Replace(pattern, "\\*", ".*", -1)
		pattern = strings.Replace(pattern, "\\?", ".", -1)
		opts.AllowOrigins[i] = "^" + pattern + "$"
	}
	return func(res http.ResponseWriter, req *http.Request) {
		var (
			origin           = req.Header.Get(headerOrigin)
			requestedMethod  = req.Header.Get(headerRequestMethod)
			requestedHeaders = req.Header.Get(headerRequestHeaders)
			// additional headers to be added
			// to the response.
			headers map[string]string
		)

		if req.Method == "OPTIONS" &&
			(requestedMethod != "" || requestedHeaders != "") {
			// TODO: if preflight, respond with exact headers if allowed
			headers = opts.PreflightHeader(origin, requestedMethod, requestedHeaders)
		} else {
			headers = opts.Header(origin)
		}

		for key, value := range headers {
			res.Header().Set(key, value)
		}
	}
}
<commit_msg>Generate and append patterns to new slice value<commit_after>// Copyright 2014 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package cors provides handlers to enable CORS support.
package cors

import (
	"net/http"
	"regexp"
	"strconv"
	"strings"
	"time"
)

const (
	headerAllowOrigin      = "Access-Control-Allow-Origin"
	headerAllowCredentials = "Access-Control-Allow-Credentials"
	headerAllowHeaders     = "Access-Control-Allow-Headers"
	headerAllowMethods     = "Access-Control-Allow-Methods"
	headerExposeHeaders    = "Access-Control-Expose-Headers"
	headerMaxAge           = "Access-Control-Max-Age"

	headerOrigin         = "Origin"
	headerRequestMethod  = "Access-Control-Request-Method"
	headerRequestHeaders = "Access-Control-Request-Headers"
)

var defaultAllowHeaders = []string{"Origin", "Accept", "Content-Type", "Authorization"}

// Represents Access Control options.
type Options struct {
	// If set, all origins are allowed.
	AllowAllOrigins bool
	// A list of allowed origins. Wild cards and FQDNs are supported.
	AllowOrigins []string
	// Regex patterns are generated from AllowOrigins. These are used and generated internally.
	AllowPatterns []string
	// If set, allows to share auth credentials such as cookies.
	AllowCredentials bool
	// A list of allowed HTTP methods.
	AllowMethods []string
	// A list of allowed HTTP headers.
	AllowHeaders []string
	// A list of exposed HTTP headers.
	ExposeHeaders []string
	// Max age of the CORS headers.
	MaxAge time.Duration
}

// Converts options into CORS headers.
func (o *Options) Header(origin string) (headers map[string]string) {
	headers = make(map[string]string)
	// if origin is not alowed, don't extend the headers
	// with CORS headers.
	if !o.AllowAllOrigins && !o.IsOriginAllowed(origin) {
		return
	}

	// add allow origin
	if o.AllowAllOrigins {
		headers[headerAllowOrigin] = "*"
	} else {
		headers[headerAllowOrigin] = origin
	}

	// add allow credentials
	headers[headerAllowCredentials] = strconv.FormatBool(o.AllowCredentials)

	// add allow methods
	if len(o.AllowMethods) > 0 {
		headers[headerAllowMethods] = strings.Join(o.AllowMethods, ",")
	}

	// add allow headers
	if len(o.AllowHeaders) > 0 {
		// TODO: Add default headers
		headers[headerAllowHeaders] = strings.Join(o.AllowHeaders, ",")
	}

	// add exposed header
	if len(o.ExposeHeaders) > 0 {
		headers[headerExposeHeaders] = strings.Join(o.ExposeHeaders, ",")
	}
	// add a max age header
	if o.MaxAge > time.Duration(0) {
		headers[headerMaxAge] = strconv.FormatInt(int64(o.MaxAge/time.Second), 10)
	}
	return
}

// Converts options into CORS headers for a preflight response.
func (o *Options) PreflightHeader(origin, rMethod, rHeaders string) (headers map[string]string) {
	headers = make(map[string]string)
	if !o.AllowAllOrigins && !o.IsOriginAllowed(origin) {
		return
	}
	// verify if requested method is allowed
	// TODO: Too many for loops
	for _, method := range o.AllowMethods {
		if method == rMethod {
			headers[headerAllowMethods] = strings.Join(o.AllowMethods, ",")
			break
		}
	}

	// verify if requested headers are allowed
	var allowed []string
	for _, rHeader := range strings.Split(rHeaders, ",") {
		rHeader = strings.TrimSpace(rHeader)
	lookupLoop:
		for _, allowedHeader := range o.AllowHeaders {
			if strings.ToLower(rHeader) == strings.ToLower(allowedHeader) {
				allowed = append(allowed, rHeader)
				break lookupLoop
			}
		}
	}

	// add allow origin
	if o.AllowAllOrigins {
		headers[headerAllowOrigin] = "*"
	} else {
		headers[headerAllowOrigin] = origin
	}

	// add allowed headers
	if len(allowed) > 0 {
		headers[headerAllowHeaders] = strings.Join(allowed, ",")
	}

	// add exposed headers
	if len(o.ExposeHeaders) > 0 {
		headers[headerExposeHeaders] = strings.Join(o.ExposeHeaders, ",")
	}
	// add a max age header
	if o.MaxAge > time.Duration(0) {
		headers[headerMaxAge] = strconv.FormatInt(int64(o.MaxAge/time.Second), 10)
	}
	return
}

// Looks up if the origin matches one of the patterns
// provided in Options.AllowOrigins patterns.
func (o *Options) IsOriginAllowed(origin string) (allowed bool) {
	for _, pattern := range o.AllowPatterns {
		allowed, _ = regexp.MatchString(pattern, origin)
		if allowed {
			return
		}
	}
	return
}

// Allows CORS for requests those match the provided options.
func Allow(opts *Options) http.HandlerFunc {
	// Allow default headers if nothing is specified.
	if len(opts.AllowHeaders) == 0 {
		opts.AllowHeaders = defaultAllowHeaders
	}

	for _, origin := range opts.AllowOrigins {
		pattern := regexp.QuoteMeta(origin)
		pattern = strings.Replace(pattern, "\\*", ".*", -1)
		pattern = strings.Replace(pattern, "\\?", ".", -1)
		opts.AllowPatterns = append(opts.AllowPatterns, "^"+pattern+"$")
	}

	return func(res http.ResponseWriter, req *http.Request) {
		var (
			origin           = req.Header.Get(headerOrigin)
			requestedMethod  = req.Header.Get(headerRequestMethod)
			requestedHeaders = req.Header.Get(headerRequestHeaders)
			// additional headers to be added
			// to the response.
			headers map[string]string
		)

		if req.Method == "OPTIONS" &&
			(requestedMethod != "" || requestedHeaders != "") {
			// TODO: if preflight, respond with exact headers if allowed
			headers = opts.PreflightHeader(origin, requestedMethod, requestedHeaders)
		} else {
			headers = opts.Header(origin)
		}

		for key, value := range headers {
			res.Header().Set(key, value)
		}
	}
}
<|endoftext|>


<commit_before>package cors

import (
	"errors"
	"strings"
	"time"

	"github.com/gin-gonic/gin"
)

// Config represents all available options for the middleware.
type Config struct {
	AllowAllOrigins bool

	// AllowOrigins is a list of origins a cross-domain request can be executed from.
	// If the special "*" value is present in the list, all origins will be allowed.
	// Default value is []
	AllowOrigins []string

	// AllowOriginFunc is a custom function to validate the origin. It take the origin
	// as argument and returns true if allowed or false otherwise. If this option is
	// set, the content of AllowOrigins is ignored.
	AllowOriginFunc func(origin string) bool

	// AllowMethods is a list of methods the client is allowed to use with
	// cross-domain requests. Default value is simple methods (GET and POST)
	AllowMethods []string

	// AllowHeaders is list of non simple headers the client is allowed to use with
	// cross-domain requests.
	AllowHeaders []string

	// AllowCredentials indicates whether the request can include user credentials like
	// cookies, HTTP authentication or client side SSL certificates.
	AllowCredentials bool

	// ExposeHeaders indicates which headers are safe to expose to the API of a CORS
	// API specification
	ExposeHeaders []string

	// MaxAge indicates how long (with second-precision) the results of a preflight request
	// can be cached
	MaxAge time.Duration

	// Allows to add origins like http://some-domain/*, https://api.* or http://some.*.subdomain.com
	AllowWildcard bool

	// Allows usage of popular browser extensions schemas
	AllowBrowserExtensions bool

	// Allows usage of WebSocket protocol
	AllowWebSockets bool

	// Allows usage of file:// schema (dangerous!) use it only when you 100% sure it's needed
	AllowFiles bool
}

// AddAllowMethods is allowed to add custom methods
func (c *Config) AddAllowMethods(methods ...string) {
	c.AllowMethods = append(c.AllowMethods, methods...)
}

// AddAllowHeaders is allowed to add custom headers
func (c *Config) AddAllowHeaders(headers ...string) {
	c.AllowHeaders = append(c.AllowHeaders, headers...)
}

// AddExposeHeaders is allowed to add custom expose headers
func (c *Config) AddExposeHeaders(headers ...string) {
	c.ExposeHeaders = append(c.ExposeHeaders, headers...)
}

func (c Config) getAllowedSchemas() []string {
	allowedSchemas := DefaultSchemas
	if c.AllowBrowserExtensions {
		allowedSchemas = append(allowedSchemas, ExtensionSchemas...)
	}
	if c.AllowWebSockets {
		allowedSchemas = append(allowedSchemas, WebSocketSchemas...)
	}
	if c.AllowFiles {
		allowedSchemas = append(allowedSchemas, FileSchemas...)
	}
	return allowedSchemas
}

func (c Config) validateAllowedSchemas(origin string) bool {
	allowedSchemas := c.getAllowedSchemas()
	for _, schema := range allowedSchemas {
		if strings.HasPrefix(origin, schema) {
			return true
		}
	}
	return false
}

// Validate is check configuration of user defined.
func (c Config) Validate() error {
	if c.AllowAllOrigins && (c.AllowOriginFunc != nil || len(c.AllowOrigins) > 0) {
		return errors.New("conflict settings: all origins are allowed. AllowOriginFunc or AllowOrigins is not needed")
	}
	if !c.AllowAllOrigins && c.AllowOriginFunc == nil && len(c.AllowOrigins) == 0 {
		return errors.New("conflict settings: all origins disabled")
	}
	for _, origin := range c.AllowOrigins {
		if !strings.Contains(origin, "*") && !c.validateAllowedSchemas(origin) {
			return errors.New("bad origin: origins must contain '*' or include " + strings.Join(c.getAllowedSchemas(), ","))
		}
	}
	return nil
}

func (c Config) parseWildcardRules() [][]string {
	var wRules [][]string

	if !c.AllowWildcard {
		return wRules
	}

	for _, o := range c.AllowOrigins {
		if !strings.Contains(o, "*") {
			continue
		}

		if c := strings.Count(o, "*"); c > 1 {
			panic(errors.New("only one * is allowed").Error())
		}

		i := strings.Index(o, "*")
		if i == 0 {
			wRules = append(wRules, []string{"*", o[1:]})
			continue
		}
		if i == (len(o) - 1) {
			wRules = append(wRules, []string{o[:i-1], "*"})
			continue
		}

		wRules = append(wRules, []string{o[:i], o[i+1:]})
	}

	return wRules
}

// DefaultConfig returns a generic default configuration mapped to localhost.
func DefaultConfig() Config {
	return Config{
		AllowMethods:     []string{"GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"},
		AllowHeaders:     []string{"Origin", "Content-Length", "Content-Type"},
		AllowCredentials: false,
		MaxAge:           12 * time.Hour,
	}
}

// Default returns the location middleware with default configuration.
func Default() gin.HandlerFunc {
	config := DefaultConfig()
	config.AllowAllOrigins = true
	return New(config)
}

// New returns the location middleware with user-defined custom configuration.
func New(config Config) gin.HandlerFunc {
	cors := newCors(config)
	return func(c *gin.Context) {
		cors.applyCors(c)
	}
}
<commit_msg>chore: update the default methods comment<commit_after>package cors

import (
	"errors"
	"strings"
	"time"

	"github.com/gin-gonic/gin"
)

// Config represents all available options for the middleware.
type Config struct {
	AllowAllOrigins bool

	// AllowOrigins is a list of origins a cross-domain request can be executed from.
	// If the special "*" value is present in the list, all origins will be allowed.
	// Default value is []
	AllowOrigins []string

	// AllowOriginFunc is a custom function to validate the origin. It take the origin
	// as argument and returns true if allowed or false otherwise. If this option is
	// set, the content of AllowOrigins is ignored.
	AllowOriginFunc func(origin string) bool

	// AllowMethods is a list of methods the client is allowed to use with
	// cross-domain requests. Default value is simple methods (GET, POST, PUT, PATCH, DELETE, HEAD, and OPTIONS)
	AllowMethods []string

	// AllowHeaders is list of non simple headers the client is allowed to use with
	// cross-domain requests.
	AllowHeaders []string

	// AllowCredentials indicates whether the request can include user credentials like
	// cookies, HTTP authentication or client side SSL certificates.
	AllowCredentials bool

	// ExposeHeaders indicates which headers are safe to expose to the API of a CORS
	// API specification
	ExposeHeaders []string

	// MaxAge indicates how long (with second-precision) the results of a preflight request
	// can be cached
	MaxAge time.Duration

	// Allows to add origins like http://some-domain/*, https://api.* or http://some.*.subdomain.com
	AllowWildcard bool

	// Allows usage of popular browser extensions schemas
	AllowBrowserExtensions bool

	// Allows usage of WebSocket protocol
	AllowWebSockets bool

	// Allows usage of file:// schema (dangerous!) use it only when you 100% sure it's needed
	AllowFiles bool
}

// AddAllowMethods is allowed to add custom methods
func (c *Config) AddAllowMethods(methods ...string) {
	c.AllowMethods = append(c.AllowMethods, methods...)
}

// AddAllowHeaders is allowed to add custom headers
func (c *Config) AddAllowHeaders(headers ...string) {
	c.AllowHeaders = append(c.AllowHeaders, headers...)
}

// AddExposeHeaders is allowed to add custom expose headers
func (c *Config) AddExposeHeaders(headers ...string) {
	c.ExposeHeaders = append(c.ExposeHeaders, headers...)
}

func (c Config) getAllowedSchemas() []string {
	allowedSchemas := DefaultSchemas
	if c.AllowBrowserExtensions {
		allowedSchemas = append(allowedSchemas, ExtensionSchemas...)
	}
	if c.AllowWebSockets {
		allowedSchemas = append(allowedSchemas, WebSocketSchemas...)
	}
	if c.AllowFiles {
		allowedSchemas = append(allowedSchemas, FileSchemas...)
	}
	return allowedSchemas
}

func (c Config) validateAllowedSchemas(origin string) bool {
	allowedSchemas := c.getAllowedSchemas()
	for _, schema := range allowedSchemas {
		if strings.HasPrefix(origin, schema) {
			return true
		}
	}
	return false
}

// Validate is check configuration of user defined.
func (c Config) Validate() error {
	if c.AllowAllOrigins && (c.AllowOriginFunc != nil || len(c.AllowOrigins) > 0) {
		return errors.New("conflict settings: all origins are allowed. AllowOriginFunc or AllowOrigins is not needed")
	}
	if !c.AllowAllOrigins && c.AllowOriginFunc == nil && len(c.AllowOrigins) == 0 {
		return errors.New("conflict settings: all origins disabled")
	}
	for _, origin := range c.AllowOrigins {
		if !strings.Contains(origin, "*") && !c.validateAllowedSchemas(origin) {
			return errors.New("bad origin: origins must contain '*' or include " + strings.Join(c.getAllowedSchemas(), ","))
		}
	}
	return nil
}

func (c Config) parseWildcardRules() [][]string {
	var wRules [][]string

	if !c.AllowWildcard {
		return wRules
	}

	for _, o := range c.AllowOrigins {
		if !strings.Contains(o, "*") {
			continue
		}

		if c := strings.Count(o, "*"); c > 1 {
			panic(errors.New("only one * is allowed").Error())
		}

		i := strings.Index(o, "*")
		if i == 0 {
			wRules = append(wRules, []string{"*", o[1:]})
			continue
		}
		if i == (len(o) - 1) {
			wRules = append(wRules, []string{o[:i-1], "*"})
			continue
		}

		wRules = append(wRules, []string{o[:i], o[i+1:]})
	}

	return wRules
}

// DefaultConfig returns a generic default configuration mapped to localhost.
func DefaultConfig() Config {
	return Config{
		AllowMethods:     []string{"GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"},
		AllowHeaders:     []string{"Origin", "Content-Length", "Content-Type"},
		AllowCredentials: false,
		MaxAge:           12 * time.Hour,
	}
}

// Default returns the location middleware with default configuration.
func Default() gin.HandlerFunc {
	config := DefaultConfig()
	config.AllowAllOrigins = true
	return New(config)
}

// New returns the location middleware with user-defined custom configuration.
func New(config Config) gin.HandlerFunc {
	cors := newCors(config)
	return func(c *gin.Context) {
		cors.applyCors(c)
	}
}
<|endoftext|>


<commit_before>// This library implements a cron spec parser and runner.  See the README for
// more details.
package cron

import (
	"sort"
	"time"
)

type entries []*Entry

// Cron keeps track of any number of entries, invoking the associated func as
// specified by the schedule. It may be started, stopped, and the entries may
// be inspected while running.
type Cron struct {
	entries  entries
	stop     chan struct{}
	add      chan *Entry
	remove   chan string
	snapshot chan entries
	running  bool
}

// Job is an interface for submitted cron jobs.
type Job interface {
	Run()
}

// The Schedule describes a job's duty cycle.
type Schedule interface {
	// Return the next activation time, later than the given time.
	// Next is invoked initially, and then each time the job is run.
	Next(time.Time) time.Time
}

// Entry consists of a schedule and the func to execute on that schedule.
type Entry struct {
	// The schedule on which this job should be run.
	Schedule Schedule

	// The next time the job will run. This is the zero time if Cron has not been
	// started or this entry's schedule is unsatisfiable
	Next time.Time

	// The last time this job was run. This is the zero time if the job has never
	// been run.
	Prev time.Time

	// The Job to run.
	Job Job

	// Unique name to identify the Entry so as to be able to remove it later.
	Name string
}

// byTime is a wrapper for sorting the entry array by time
// (with zero time at the end).
type byTime []*Entry

func (s byTime) Len() int      { return len(s) }
func (s byTime) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s byTime) Less(i, j int) bool {
	// Two zero times should return false.
	// Otherwise, zero is "greater" than any other time.
	// (To sort it at the end of the list.)
	if s[i].Next.IsZero() {
		return false
	}
	if s[j].Next.IsZero() {
		return true
	}
	return s[i].Next.Before(s[j].Next)
}

// New returns a new Cron job runner.
func New() *Cron {
	return &Cron{
		entries:  nil,
		add:      make(chan *Entry),
		remove:   make(chan string),
		stop:     make(chan struct{}),
		snapshot: make(chan entries),
		running:  false,
	}
}

// A wrapper that turns a func() into a cron.Job
type FuncJob func()

func (f FuncJob) Run() { f() }

// AddFunc adds a func to the Cron to be run on the given schedule.
func (c *Cron) AddFunc(spec string, cmd func(), name string) {
	c.AddJob(spec, FuncJob(cmd), name)
}

// AddFunc adds a Job to the Cron to be run on the given schedule.
func (c *Cron) AddJob(spec string, cmd Job, name string) {
	c.Schedule(Parse(spec), cmd, name)
}

// RemoveJob removes a Job from the Cron based on name.
func (c *Cron) RemoveJob(name string) {
	if !c.running {
		i := c.entries.pos(name)

		if i == -1 {
			return
		}

		c.entries = c.entries[:i+copy(c.entries[i:], c.entries[i+1:])]
		return
	}

	c.remove <- name
}

func (entrySlice entries) pos(name string) int {
	for p, e := range entrySlice {
		if e.Name == name {
			return p
		}
	}
	return -1
}

// Schedule adds a Job to the Cron to be run on the given schedule.
func (c *Cron) Schedule(schedule Schedule, cmd Job, name string) {
	entry := &Entry{
		Schedule: schedule,
		Job:      cmd,
		Name:     name,
	}

	if !c.running {
		i := c.entries.pos(entry.Name)
		if i != -1 {
			return
		}
		c.entries = append(c.entries, entry)
		return
	}

	c.add <- entry
}

// Entries returns a snapshot of the cron entries.
func (c *Cron) Entries() []*Entry {
	if c.running {
		c.snapshot <- nil
		x := <-c.snapshot
		return x
	}
	return c.entrySnapshot()
}

// Start the cron scheduler in its own go-routine.
func (c *Cron) Start() {
	c.running = true
	go c.run()
}

// Run the scheduler.. this is private just due to the need to synchronize
// access to the 'running' state variable.
func (c *Cron) run() {
	// Figure out the next activation times for each entry.
	now := time.Now().Local()
	for _, entry := range c.entries {
		entry.Next = entry.Schedule.Next(now)
	}

	for {
		// Determine the next entry to run.
		sort.Sort(byTime(c.entries))

		var effective time.Time
		if len(c.entries) == 0 || c.entries[0].Next.IsZero() {
			// If there are no entries yet, just sleep - it still handles new entries
			// and stop requests.
			effective = now.AddDate(10, 0, 0)
		} else {
			effective = c.entries[0].Next
		}

		select {
		case now = <-time.After(effective.Sub(now)):
			// Run every entry whose next time was this effective time.
			for _, e := range c.entries {
				if e.Next != effective {
					break
				}
				go e.Job.Run()
				e.Prev = e.Next
				e.Next = e.Schedule.Next(effective)
			}
			continue

		case newEntry := <-c.add:
			i := c.entries.pos(newEntry.Name)
			if i != -1 {
				break
			}
			c.entries = append(c.entries, newEntry)
			newEntry.Next = newEntry.Schedule.Next(now)

		case name := <-c.remove:
			i := c.entries.pos(name)

			if i == -1 {
				break
			}

			c.entries = c.entries[:i+copy(c.entries[i:], c.entries[i+1:])]

		case <-c.snapshot:
			c.snapshot <- c.entrySnapshot()

		case <-c.stop:
			return
		}

		// 'now' should be updated after newEntry and snapshot cases.
		now = time.Now().Local()
	}
}

// Stop the cron scheduler.
func (c *Cron) Stop() {
	c.stop <- struct{}{}
	c.running = false
}

// entrySnapshot returns a copy of the current cron entry list.
func (c *Cron) entrySnapshot() []*Entry {
	entries := []*Entry{}
	for _, e := range c.entries {
		entries = append(entries, &Entry{
			Schedule: e.Schedule,
			Next:     e.Next,
			Prev:     e.Prev,
			Job:      e.Job,
		})
	}
	return entries
}
<commit_msg>fixd addjob first run bug<commit_after>// This library implements a cron spec parser and runner.  See the README for
// more details.
package cron

import (
	"sort"
	"time"
)

type entries []*Entry

// Cron keeps track of any number of entries, invoking the associated func as
// specified by the schedule. It may be started, stopped, and the entries may
// be inspected while running.
type Cron struct {
	entries  entries
	stop     chan struct{}
	add      chan *Entry
	remove   chan string
	snapshot chan entries
	running  bool
}

// Job is an interface for submitted cron jobs.
type Job interface {
	Run()
}

// The Schedule describes a job's duty cycle.
type Schedule interface {
	// Return the next activation time, later than the given time.
	// Next is invoked initially, and then each time the job is run.
	Next(time.Time) time.Time
}

// Entry consists of a schedule and the func to execute on that schedule.
type Entry struct {
	// The schedule on which this job should be run.
	Schedule Schedule

	// The next time the job will run. This is the zero time if Cron has not been
	// started or this entry's schedule is unsatisfiable
	Next time.Time

	// The last time this job was run. This is the zero time if the job has never
	// been run.
	Prev time.Time

	// The Job to run.
	Job Job

	// Unique name to identify the Entry so as to be able to remove it later.
	Name string
}

// byTime is a wrapper for sorting the entry array by time
// (with zero time at the end).
type byTime []*Entry

func (s byTime) Len() int      { return len(s) }
func (s byTime) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s byTime) Less(i, j int) bool {
	// Two zero times should return false.
	// Otherwise, zero is "greater" than any other time.
	// (To sort it at the end of the list.)
	if s[i].Next.IsZero() {
		return false
	}
	if s[j].Next.IsZero() {
		return true
	}
	return s[i].Next.Before(s[j].Next)
}

// New returns a new Cron job runner.
func New() *Cron {
	return &Cron{
		entries:  nil,
		add:      make(chan *Entry),
		remove:   make(chan string),
		stop:     make(chan struct{}),
		snapshot: make(chan entries),
		running:  false,
	}
}

// A wrapper that turns a func() into a cron.Job
type FuncJob func()

func (f FuncJob) Run() { f() }

// AddFunc adds a func to the Cron to be run on the given schedule.
func (c *Cron) AddFunc(spec string, cmd func(), name string) {
	c.AddJob(spec, FuncJob(cmd), name)
}

// AddFunc adds a Job to the Cron to be run on the given schedule.
func (c *Cron) AddJob(spec string, cmd Job, name string) {
	c.Schedule(Parse(spec), cmd, name)
}

// RemoveJob removes a Job from the Cron based on name.
func (c *Cron) RemoveJob(name string) {
	if !c.running {
		i := c.entries.pos(name)

		if i == -1 {
			return
		}

		c.entries = c.entries[:i+copy(c.entries[i:], c.entries[i+1:])]
		return
	}

	c.remove <- name
}

func (entrySlice entries) pos(name string) int {
	for p, e := range entrySlice {
		if e.Name == name {
			return p
		}
	}
	return -1
}

// Schedule adds a Job to the Cron to be run on the given schedule.
func (c *Cron) Schedule(schedule Schedule, cmd Job, name string) {
	entry := &Entry{
		Schedule: schedule,
		Job:      cmd,
		Name:     name,
	}

	if !c.running {
		i := c.entries.pos(entry.Name)
		if i != -1 {
			return
		}
		c.entries = append(c.entries, entry)
		return
	}

	c.add <- entry
}

// Entries returns a snapshot of the cron entries.
func (c *Cron) Entries() []*Entry {
	if c.running {
		c.snapshot <- nil
		x := <-c.snapshot
		return x
	}
	return c.entrySnapshot()
}

// Start the cron scheduler in its own go-routine.
func (c *Cron) Start() {
	c.running = true
	go c.run()
}

// Run the scheduler.. this is private just due to the need to synchronize
// access to the 'running' state variable.
func (c *Cron) run() {
	// Figure out the next activation times for each entry.
	now := time.Now().Local()
	for _, entry := range c.entries {
		entry.Next = entry.Schedule.Next(now)
	}

	for {
		// Determine the next entry to run.
		sort.Sort(byTime(c.entries))

		var effective time.Time
		if len(c.entries) == 0 || c.entries[0].Next.IsZero() {
			// If there are no entries yet, just sleep - it still handles new entries
			// and stop requests.
			effective = now.AddDate(10, 0, 0)
		} else {
			effective = c.entries[0].Next
		}

		select {
		case now = <-time.After(effective.Sub(now)):
			// Run every entry whose next time was this effective time.
			for _, e := range c.entries {
				if e.Next != effective {
					break
				}
				go e.Job.Run()
				e.Prev = e.Next
				e.Next = e.Schedule.Next(effective)
			}
			continue

		case newEntry := <-c.add:
			i := c.entries.pos(newEntry.Name)
			if i != -1 {
				break
			}
			c.entries = append(c.entries, newEntry)
			newEntry.Next = newEntry.Schedule.Next(time.Now().Local())

		case name := <-c.remove:
			i := c.entries.pos(name)

			if i == -1 {
				break
			}

			c.entries = c.entries[:i+copy(c.entries[i:], c.entries[i+1:])]

		case <-c.snapshot:
			c.snapshot <- c.entrySnapshot()

		case <-c.stop:
			return
		}

		// 'now' should be updated after newEntry and snapshot cases.
		now = time.Now().Local()
	}
}

// Stop the cron scheduler.
func (c *Cron) Stop() {
	c.stop <- struct{}{}
	c.running = false
}

// entrySnapshot returns a copy of the current cron entry list.
func (c *Cron) entrySnapshot() []*Entry {
	entries := []*Entry{}
	for _, e := range c.entries {
		entries = append(entries, &Entry{
			Schedule: e.Schedule,
			Next:     e.Next,
			Prev:     e.Prev,
			Job:      e.Job,
		})
	}
	return entries
}
<|endoftext|>