<commit_before>package web

import (
	"encoding/json"
	"encoding/xml"
	"errors"
	"net/http"
	"net/url"
	"reflect"
	"strconv"
)

// createContext return a web.Context
func createContext(w http.ResponseWriter, r *http.Request, params *Params) *Context {

	ctx := &Context{
		ResponseWriter: w,
		Request:        r,
		params:         params,
	}

	return ctx
}

// Context is type of an web.Context
type Context struct {
	ResponseWriter http.ResponseWriter
	Request        *http.Request
	params         *Params
	urlValues      *url.Values
	UserID         uint64
}

// Param get value from Params
func (ctx *Context) Param(name string) string {
	return ctx.params.Val(name)
}

// Query get value from QueryString
func (ctx *Context) Query(name string) string {
	if ctx.urlValues == nil {
		urlValues := ctx.Request.URL.Query()
		ctx.urlValues = &urlValues
	}

	return ctx.urlValues.Get(name)
}

// Form get value from Form
func (ctx *Context) Form(name string) string {
	if ctx.Request.Form == nil {
		ctx.Request.ParseForm()
	}
	return ctx.Request.Form.Get(name)
}

// TryParse try parse val to v
func (ctx *Context) TryParse(val string, v interface{}) error {
	if v == nil {
		return errors.New("TryParse(nil)")
	}

	rv := reflect.ValueOf(v)

	if rv.Kind() != reflect.Ptr {
		return errors.New("TryParse(non-pointer " + reflect.TypeOf(v).String() + ")")
	}

	if rv.IsNil() {
		return errors.New("TryParse(nil)")
	}

	for rv.Kind() == reflect.Ptr && !rv.IsNil() {
		rv = rv.Elem()
	}

	if !rv.CanSet() {
		return errors.New("TryParse(can not set value to v)")
	}

	switch rv.Interface().(type) {
	case string:
		rv.SetString(val)
		return nil
	case int, int64:
		d, err := strconv.ParseInt(val, 10, 64)
		if err != nil {
			return err
		}
		rv.SetInt(d)
		return nil
	case int32:
		d, err := strconv.ParseInt(val, 10, 32)
		if err != nil {
			return err
		}
		rv.SetInt(d)
		return nil
	default:
		return json.Unmarshal([]byte(val), v)
	}
}

// Parse parse val to v, if error abort
func (ctx *Context) Parse(val string, v interface{}) {
	ctx.Abort(ctx.TryParse(val, v))
}

// TryParseBody decode val from Request.Body
func (ctx *Context) TryParseBody(val interface{}) error {
	if err := json.NewDecoder(ctx.Request.Body).Decode(val); err != nil {
		return err
	}
	defer ctx.Request.Body.Close()
	return nil
}

// ParseBody decode val from Request.Body, if error abort
func (ctx *Context) ParseBody(val interface{}) {
	ctx.Abort(ctx.TryParseBody(val))
}

// TryParseParam decode val from Query
func (ctx *Context) TryParseParam(name string, val interface{}) error {
	return ctx.TryParse(ctx.Param(name), val)
}

// ParseParam decode val from Param, if error abort
func (ctx *Context) ParseParam(name string, val interface{}) {
	ctx.Abort(ctx.TryParseParam(name, val))
}

// TryParseQuery decode val from Query
func (ctx *Context) TryParseQuery(name string, val interface{}) error {
	return ctx.TryParse(ctx.Query(name), val)
}

// ParseQuery decode val from Query, if error abort
func (ctx *Context) ParseQuery(name string, val interface{}) {
	ctx.Abort(ctx.TryParseQuery(name, val))
}

// TryParseForm decode val from Form
func (ctx *Context) TryParseForm(name string, val interface{}) error {
	return ctx.TryParse(ctx.Form(name), val)
}

// ParseForm decode val from Form, if error abort
func (ctx *Context) ParseForm(name string, val interface{}) {
	ctx.Abort(ctx.TryParseForm(name, val))
}

// Abort if error about with 400
func (ctx *Context) Abort(err error) {
	if err != nil {
		ctx.WriteHeader(defaultHTTPError)
		ctx.WriteJSON(err.Error())
		panic(err)
	}
}

// AbortIf if error abort with 400
// else response val with 200
func (ctx *Context) AbortIf(val interface{}, err error) {
	if err != nil {
		ctx.WriteHeader(defaultHTTPError)
		ctx.WriteJSON(err.Error())
		panic(err)
	} else {
		ctx.WriteHeader(defaultHTTPSuccess)
		ctx.WriteJSON(val)
	}
}

// Unauthorized if error abort with 401
func (ctx *Context) Unauthorized(err error) {
	if err != nil {
		ctx.WriteHeader(401)
		ctx.WriteJSON(err.Error())
		panic(err)
	}
}

// Forbidden if error abort with 403
func (ctx *Context) Forbidden(err error) {
	if err != nil {
		ctx.WriteHeader(403)
		ctx.WriteJSON(err.Error())
		panic(err)
	}
}

// GetHeader get header by key
func (ctx *Context) GetHeader(key string) string {
	return ctx.Request.Header.Get(key)
}

// Write bytes
func (ctx *Context) Write(val []byte) (int, error) {
	return ctx.ResponseWriter.Write(val)
}

// WriteString Write String
func (ctx *Context) WriteString(val string) (int, error) {
	return ctx.ResponseWriter.Write([]byte(val))
}

// WriteJSON Write JSON
func (ctx *Context) WriteJSON(val interface{}) error {
	return json.NewEncoder(ctx.ResponseWriter).Encode(val)
}

// WriteXML Write XML
func (ctx *Context) WriteXML(val interface{}) error {
	return xml.NewEncoder(ctx.ResponseWriter).Encode(val)
}

// WriteHeader Write Header
func (ctx *Context) WriteHeader(statusCode int) {
	ctx.ResponseWriter.WriteHeader(statusCode)
}

// SetHeader Set Header
func (ctx *Context) SetHeader(key string, value string) {
	ctx.ResponseWriter.Header().Set(key, value)
}

// AddHeader Add Header
func (ctx *Context) AddHeader(key string, value string) {
	ctx.ResponseWriter.Header().Add(key, value)
}

// GetContentType get Content-Type
func (ctx *Context) GetContentType() string {
	return ctx.GetHeader("Content-Type")
}

// SetContentType Set Content-Type
func (ctx *Context) SetContentType(val string) {
	ctx.SetHeader("Content-Type", contentType(val))
}

// Redirect to url with status
func (ctx *Context) Redirect(status int, url string) {
	ctx.SetHeader("Location", url)
	ctx.WriteHeader(status)
	ctx.WriteString("Redirecting to: " + url)
}
<commit_msg>add short hand<commit_after>package web

import (
	"encoding/json"
	"encoding/xml"
	"errors"
	"net/http"
	"net/url"
	"reflect"
	"strconv"
)

// createContext return a web.Context
func createContext(w http.ResponseWriter, r *http.Request, params *Params) *Context {

	ctx := &Context{
		ResponseWriter: w,
		Request:        r,
		params:         params,
	}

	return ctx
}

// Context is type of an web.Context
type Context struct {
	ResponseWriter http.ResponseWriter
	Request        *http.Request
	params         *Params
	urlValues      *url.Values
	UserID         uint64
}

// P get value from Params
func (ctx *Context) P(name string) string {
	return ctx.Param(name)
}

// Q get value from QueryString
func (ctx *Context) Q(name string) string {
	return ctx.Query(name)
}

// F get value from Form
func (ctx *Context) F(name string) string {
	return ctx.Form(name)
}

// Param get value from Params
func (ctx *Context) Param(name string) string {
	return ctx.params.Val(name)
}

// Query get value from QueryString
func (ctx *Context) Query(name string) string {
	if ctx.urlValues == nil {
		urlValues := ctx.Request.URL.Query()
		ctx.urlValues = &urlValues
	}

	return ctx.urlValues.Get(name)
}

// Form get value from Form
func (ctx *Context) Form(name string) string {
	if ctx.Request.Form == nil {
		ctx.Request.ParseForm()
	}
	return ctx.Request.Form.Get(name)
}

// TryParse try parse val to v
func (ctx *Context) TryParse(val string, v interface{}) error {
	if v == nil {
		return errors.New("TryParse(nil)")
	}

	rv := reflect.ValueOf(v)

	if rv.Kind() != reflect.Ptr {
		return errors.New("TryParse(non-pointer " + reflect.TypeOf(v).String() + ")")
	}

	if rv.IsNil() {
		return errors.New("TryParse(nil)")
	}

	for rv.Kind() == reflect.Ptr && !rv.IsNil() {
		rv = rv.Elem()
	}

	if !rv.CanSet() {
		return errors.New("TryParse(can not set value to v)")
	}

	switch rv.Interface().(type) {
	case string:
		rv.SetString(val)
		return nil
	case int, int64:
		d, err := strconv.ParseInt(val, 10, 64)
		if err != nil {
			return err
		}
		rv.SetInt(d)
		return nil
	case int32:
		d, err := strconv.ParseInt(val, 10, 32)
		if err != nil {
			return err
		}
		rv.SetInt(d)
		return nil
	default:
		return json.Unmarshal([]byte(val), v)
	}
}

// Parse parse val to v, if error abort
func (ctx *Context) Parse(val string, v interface{}) {
	ctx.Abort(ctx.TryParse(val, v))
}

// TryParseBody decode val from Request.Body
func (ctx *Context) TryParseBody(val interface{}) error {
	if err := json.NewDecoder(ctx.Request.Body).Decode(val); err != nil {
		return err
	}
	defer ctx.Request.Body.Close()
	return nil
}

// ParseBody decode val from Request.Body, if error abort
func (ctx *Context) ParseBody(val interface{}) {
	ctx.Abort(ctx.TryParseBody(val))
}

// TryParseParam decode val from Query
func (ctx *Context) TryParseParam(name string, val interface{}) error {
	return ctx.TryParse(ctx.Param(name), val)
}

// ParseParam decode val from Param, if error abort
func (ctx *Context) ParseParam(name string, val interface{}) {
	ctx.Abort(ctx.TryParseParam(name, val))
}

// TryParseQuery decode val from Query
func (ctx *Context) TryParseQuery(name string, val interface{}) error {
	return ctx.TryParse(ctx.Query(name), val)
}

// ParseQuery decode val from Query, if error abort
func (ctx *Context) ParseQuery(name string, val interface{}) {
	ctx.Abort(ctx.TryParseQuery(name, val))
}

// TryParseForm decode val from Form
func (ctx *Context) TryParseForm(name string, val interface{}) error {
	return ctx.TryParse(ctx.Form(name), val)
}

// ParseForm decode val from Form, if error abort
func (ctx *Context) ParseForm(name string, val interface{}) {
	ctx.Abort(ctx.TryParseForm(name, val))
}

// Abort if error abort with 400
func (ctx *Context) Abort(err error) {
	ctx.AbortCode(defaultHTTPError, err)
}

// AbortCode if error abort with code
func (ctx *Context) AbortCode(code int, err error) {
	if err != nil {
		ctx.WriteHeader(code)
		ctx.WriteJSON(err.Error())
		panic(err)
	}
}

// AbortIf if error abort with 400
// else response val with 200
func (ctx *Context) AbortIf(val interface{}, err error) {
	if err != nil {
		ctx.WriteHeader(defaultHTTPError)
		ctx.WriteJSON(err.Error())
		panic(err)
	} else {
		ctx.WriteHeader(defaultHTTPSuccess)
		ctx.WriteJSON(val)
	}
}

// Unauthorized if error abort with 401
func (ctx *Context) Unauthorized(err error) {
	ctx.AbortCode(401, err)
}

// Forbidden if error abort with 403
func (ctx *Context) Forbidden(err error) {
	ctx.AbortCode(403, err)
}

// GetHeader get header by key
func (ctx *Context) GetHeader(key string) string {
	return ctx.Request.Header.Get(key)
}

// Write bytes
func (ctx *Context) Write(val []byte) (int, error) {
	return ctx.ResponseWriter.Write(val)
}

// WriteString Write String
func (ctx *Context) WriteString(val string) (int, error) {
	return ctx.ResponseWriter.Write([]byte(val))
}

// WriteJSON Write JSON
func (ctx *Context) WriteJSON(val interface{}) error {
	return json.NewEncoder(ctx.ResponseWriter).Encode(val)
}

// WriteXML Write XML
func (ctx *Context) WriteXML(val interface{}) error {
	return xml.NewEncoder(ctx.ResponseWriter).Encode(val)
}

// WriteHeader Write Header
func (ctx *Context) WriteHeader(statusCode int) {
	ctx.ResponseWriter.WriteHeader(statusCode)
}

// SetHeader Set Header
func (ctx *Context) SetHeader(key string, value string) {
	ctx.ResponseWriter.Header().Set(key, value)
}

// AddHeader Add Header
func (ctx *Context) AddHeader(key string, value string) {
	ctx.ResponseWriter.Header().Add(key, value)
}

// GetContentType get Content-Type
func (ctx *Context) GetContentType() string {
	return ctx.GetHeader("Content-Type")
}

// SetContentType Set Content-Type
func (ctx *Context) SetContentType(val string) {
	ctx.SetHeader("Content-Type", contentType(val))
}

// Redirect to url with status
func (ctx *Context) Redirect(status int, url string) {
	ctx.SetHeader("Location", url)
	ctx.WriteHeader(status)
	ctx.WriteString("Redirecting to: " + url)
}
<|endoftext|>


<commit_before>package gocql

import (
	"context"
	crand "crypto/rand"
	"errors"
	"fmt"
	"math/rand"
	"net"
	"regexp"
	"strconv"
	"sync"
	"sync/atomic"
	"time"
)

var (
	randr    *rand.Rand
	mutRandr sync.Mutex
)

func init() {
	b := make([]byte, 4)
	if _, err := crand.Read(b); err != nil {
		panic(fmt.Sprintf("unable to seed random number generator: %v", err))
	}

	randr = rand.New(rand.NewSource(int64(readInt(b))))
}

// Ensure that the atomic variable is aligned to a 64bit boundary
// so that atomic operations can be applied on 32bit architectures.
type controlConn struct {
	session *Session
	conn    atomic.Value

	retry RetryPolicy

	started int32
	quit    chan struct{}
}

func createControlConn(session *Session) *controlConn {
	control := &controlConn{
		session: session,
		quit:    make(chan struct{}),
		retry:   &SimpleRetryPolicy{NumRetries: 3},
	}

	control.conn.Store((*connHost)(nil))

	return control
}

func (c *controlConn) heartBeat() {
	if !atomic.CompareAndSwapInt32(&c.started, 0, 1) {
		return
	}

	sleepTime := 1 * time.Second

	for {
		select {
		case <-c.quit:
			return
		case <-time.After(sleepTime):
		}

		resp, err := c.writeFrame(&writeOptionsFrame{})
		if err != nil {
			goto reconn
		}

		switch resp.(type) {
		case *supportedFrame:
			// Everything ok
			sleepTime = 5 * time.Second
			continue
		case error:
			goto reconn
		default:
			panic(fmt.Sprintf("gocql: unknown frame in response to options: %T", resp))
		}

	reconn:
		// try to connect a bit faster
		sleepTime = 1 * time.Second
		c.reconnect(true)
		// time.Sleep(5 * time.Second)
		continue
	}
}

var hostLookupPreferV4 = false

func hostInfo(addr string, defaultPort int) (*HostInfo, error) {
	var port int
	host, portStr, err := net.SplitHostPort(addr)
	if err != nil {
		host = addr
		port = defaultPort
	} else {
		port, err = strconv.Atoi(portStr)
		if err != nil {
			return nil, err
		}
	}

	ip := net.ParseIP(host)
	if ip == nil {
		ips, err := net.LookupIP(host)
		if err != nil {
			return nil, err
		} else if len(ips) == 0 {
			return nil, fmt.Errorf("No IP's returned from DNS lookup for %q", addr)
		}

		if hostLookupPreferV4 {
			for _, v := range ips {
				if v4 := v.To4(); v4 != nil {
					ip = v4
					break
				}
			}
			if ip == nil {
				ip = ips[0]
			}
		} else {
			// TODO(zariel): should we check that we can connect to any of the ips?
			ip = ips[0]
		}

	}

	return &HostInfo{connectAddress: ip, port: port}, nil
}

func shuffleHosts(hosts []*HostInfo) []*HostInfo {
	mutRandr.Lock()
	perm := randr.Perm(len(hosts))
	mutRandr.Unlock()
	shuffled := make([]*HostInfo, len(hosts))

	for i, host := range hosts {
		shuffled[perm[i]] = host
	}

	return shuffled
}

func (c *controlConn) shuffleDial(endpoints []*HostInfo) (*Conn, error) {
	// shuffle endpoints so not all drivers will connect to the same initial
	// node.
	shuffled := shuffleHosts(endpoints)

	var err error
	for _, host := range shuffled {
		var conn *Conn
		conn, err = c.session.connect(host, c)
		if err == nil {
			return conn, nil
		}

		Logger.Printf("gocql: unable to dial control conn %v: %v\n", host.ConnectAddress(), err)
	}

	return nil, err
}

// this is going to be version dependant and a nightmare to maintain :(
var protocolSupportRe = regexp.MustCompile(`the lowest supported version is \d+ and the greatest is (\d+)$`)

func parseProtocolFromError(err error) int {
	// I really wish this had the actual info in the error frame...
	matches := protocolSupportRe.FindAllStringSubmatch(err.Error(), -1)
	if len(matches) != 1 || len(matches[0]) != 2 {
		if verr, ok := err.(*protocolError); ok {
			return int(verr.frame.Header().version.version())
		}
		return 0
	}

	max, err := strconv.Atoi(matches[0][1])
	if err != nil {
		return 0
	}

	return max
}

func (c *controlConn) discoverProtocol(hosts []*HostInfo) (int, error) {
	hosts = shuffleHosts(hosts)

	connCfg := *c.session.connCfg
	connCfg.ProtoVersion = 4 // TODO: define maxProtocol

	handler := connErrorHandlerFn(func(c *Conn, err error, closed bool) {
		// we should never get here, but if we do it means we connected to a
		// host successfully which means our attempted protocol version worked
		if !closed {
			c.Close()
		}
	})

	var err error
	for _, host := range hosts {
		var conn *Conn
		conn, err = c.session.dial(host.ConnectAddress(), host.Port(), &connCfg, handler)
		if conn != nil {
			conn.Close()
		}

		if err == nil {
			return connCfg.ProtoVersion, nil
		}

		if proto := parseProtocolFromError(err); proto > 0 {
			return proto, nil
		}
	}

	return 0, err
}

func (c *controlConn) connect(hosts []*HostInfo) error {
	if len(hosts) == 0 {
		return errors.New("control: no endpoints specified")
	}

	conn, err := c.shuffleDial(hosts)
	if err != nil {
		return fmt.Errorf("control: unable to connect to initial hosts: %v", err)
	}

	if err := c.setupConn(conn); err != nil {
		conn.Close()
		return fmt.Errorf("control: unable to setup connection: %v", err)
	}

	// we could fetch the initial ring here and update initial host data. So that
	// when we return from here we have a ring topology ready to go.

	go c.heartBeat()

	return nil
}

type connHost struct {
	conn *Conn
	host *HostInfo
}

func (c *controlConn) setupConn(conn *Conn) error {
	if err := c.registerEvents(conn); err != nil {
		conn.Close()
		return err
	}

	// TODO(zariel): do we need to fetch host info everytime
	// the control conn connects? Surely we have it cached?
	host, err := conn.localHostInfo()
	if err != nil {
		return err
	}

	ch := &connHost{
		conn: conn,
		host: host,
	}

	c.conn.Store(ch)
	// c.session.handleNodeUp(host.ConnectAddress(), host.Port(), false)

	return nil
}

func (c *controlConn) registerEvents(conn *Conn) error {
	var events []string

	if !c.session.cfg.Events.DisableTopologyEvents {
		events = append(events, "TOPOLOGY_CHANGE")
	}
	if !c.session.cfg.Events.DisableNodeStatusEvents {
		events = append(events, "STATUS_CHANGE")
	}
	if !c.session.cfg.Events.DisableSchemaEvents {
		events = append(events, "SCHEMA_CHANGE")
	}

	if len(events) == 0 {
		return nil
	}

	framer, err := conn.exec(context.Background(),
		&writeRegisterFrame{
			events: events,
		}, nil)
	if err != nil {
		return err
	}

	frame, err := framer.parseFrame()
	if err != nil {
		return err
	} else if _, ok := frame.(*readyFrame); !ok {
		return fmt.Errorf("unexpected frame in response to register: got %T: %v\n", frame, frame)
	}

	return nil
}

func (c *controlConn) reconnect(refreshring bool) {
	// TODO: simplify this function, use session.ring to get hosts instead of the
	// connection pool

	var host *HostInfo
	ch := c.getConn()
	if ch != nil {
		host = ch.host
		ch.conn.Close()
	}

	var newConn *Conn
	if host != nil {
		// try to connect to the old host
		conn, err := c.session.connect(host, c)
		if err != nil {
			// host is dead
			// TODO: this is replicated in a few places
			c.session.handleNodeDown(host.ConnectAddress(), host.Port())
		} else {
			newConn = conn
		}
	}

	// TODO: should have our own round-robin for hosts so that we can try each
	// in succession and guarantee that we get a different host each time.
	if newConn == nil {
		host := c.session.ring.rrHost()
		if host == nil {
			c.connect(c.session.ring.endpoints)
			return
		}

		var err error
		newConn, err = c.session.connect(host, c)
		if err != nil {
			// TODO: add log handler for things like this
			return
		}
	}

	if err := c.setupConn(newConn); err != nil {
		newConn.Close()
		Logger.Printf("gocql: control unable to register events: %v\n", err)
		return
	}

	if refreshring {
		c.session.hostSource.refreshRing()
	}
}

func (c *controlConn) HandleError(conn *Conn, err error, closed bool) {
	if !closed {
		return
	}

	oldConn := c.getConn()
	if oldConn.conn != conn {
		return
	}

	c.reconnect(true)
}

func (c *controlConn) getConn() *connHost {
	return c.conn.Load().(*connHost)
}

func (c *controlConn) writeFrame(w frameWriter) (frame, error) {
	ch := c.getConn()
	if ch == nil {
		return nil, errNoControl
	}

	framer, err := ch.conn.exec(context.Background(), w, nil)
	if err != nil {
		return nil, err
	}

	return framer.parseFrame()
}

func (c *controlConn) withConnHost(fn func(*connHost) *Iter) *Iter {
	const maxConnectAttempts = 5
	connectAttempts := 0

	for i := 0; i < maxConnectAttempts; i++ {
		ch := c.getConn()
		if ch == nil {
			if connectAttempts > maxConnectAttempts {
				break
			}

			connectAttempts++

			c.reconnect(false)
			continue
		}

		return fn(ch)
	}

	return &Iter{err: errNoControl}
}

func (c *controlConn) withConn(fn func(*Conn) *Iter) *Iter {
	return c.withConnHost(func(ch *connHost) *Iter {
		return fn(ch.conn)
	})
}

// query will return nil if the connection is closed or nil
func (c *controlConn) query(statement string, values ...interface{}) (iter *Iter) {
	q := c.session.Query(statement, values...).Consistency(One).RoutingKey([]byte{}).Trace(nil)

	for {
		iter = c.withConn(func(conn *Conn) *Iter {
			return conn.executeQuery(q)
		})

		if gocqlDebug && iter.err != nil {
			Logger.Printf("control: error executing %q: %v\n", statement, iter.err)
		}

		q.attempts++
		if iter.err == nil || !c.retry.Attempt(q) {
			break
		}
	}

	return
}

func (c *controlConn) awaitSchemaAgreement() error {
	return c.withConn(func(conn *Conn) *Iter {
		return &Iter{err: conn.awaitSchemaAgreement()}
	}).err
}

func (c *controlConn) close() {
	if atomic.CompareAndSwapInt32(&c.started, 1, -1) {
		c.quit <- struct{}{}
	}

	ch := c.getConn()
	if ch != nil {
		ch.conn.Close()
	}
}

var errNoControl = errors.New("gocql: no control connection available")
<commit_msg>control: prevent reconnect reentry<commit_after>package gocql

import (
	"context"
	crand "crypto/rand"
	"errors"
	"fmt"
	"math/rand"
	"net"
	"regexp"
	"strconv"
	"sync"
	"sync/atomic"
	"time"
)

var (
	randr    *rand.Rand
	mutRandr sync.Mutex
)

func init() {
	b := make([]byte, 4)
	if _, err := crand.Read(b); err != nil {
		panic(fmt.Sprintf("unable to seed random number generator: %v", err))
	}

	randr = rand.New(rand.NewSource(int64(readInt(b))))
}

// Ensure that the atomic variable is aligned to a 64bit boundary
// so that atomic operations can be applied on 32bit architectures.
type controlConn struct {
	started      int32
	reconnecting int32

	session *Session
	conn    atomic.Value

	retry RetryPolicy

	quit chan struct{}
}

func createControlConn(session *Session) *controlConn {
	control := &controlConn{
		session: session,
		quit:    make(chan struct{}),
		retry:   &SimpleRetryPolicy{NumRetries: 3},
	}

	control.conn.Store((*connHost)(nil))

	return control
}

func (c *controlConn) heartBeat() {
	if !atomic.CompareAndSwapInt32(&c.started, 0, 1) {
		return
	}

	sleepTime := 1 * time.Second

	for {
		select {
		case <-c.quit:
			return
		case <-time.After(sleepTime):
		}

		resp, err := c.writeFrame(&writeOptionsFrame{})
		if err != nil {
			goto reconn
		}

		switch resp.(type) {
		case *supportedFrame:
			// Everything ok
			sleepTime = 5 * time.Second
			continue
		case error:
			goto reconn
		default:
			panic(fmt.Sprintf("gocql: unknown frame in response to options: %T", resp))
		}

	reconn:
		// try to connect a bit faster
		sleepTime = 1 * time.Second
		c.reconnect(true)
		// time.Sleep(5 * time.Second)
		continue
	}
}

var hostLookupPreferV4 = false

func hostInfo(addr string, defaultPort int) (*HostInfo, error) {
	var port int
	host, portStr, err := net.SplitHostPort(addr)
	if err != nil {
		host = addr
		port = defaultPort
	} else {
		port, err = strconv.Atoi(portStr)
		if err != nil {
			return nil, err
		}
	}

	ip := net.ParseIP(host)
	if ip == nil {
		ips, err := net.LookupIP(host)
		if err != nil {
			return nil, err
		} else if len(ips) == 0 {
			return nil, fmt.Errorf("No IP's returned from DNS lookup for %q", addr)
		}

		if hostLookupPreferV4 {
			for _, v := range ips {
				if v4 := v.To4(); v4 != nil {
					ip = v4
					break
				}
			}
			if ip == nil {
				ip = ips[0]
			}
		} else {
			// TODO(zariel): should we check that we can connect to any of the ips?
			ip = ips[0]
		}

	}

	return &HostInfo{connectAddress: ip, port: port}, nil
}

func shuffleHosts(hosts []*HostInfo) []*HostInfo {
	mutRandr.Lock()
	perm := randr.Perm(len(hosts))
	mutRandr.Unlock()
	shuffled := make([]*HostInfo, len(hosts))

	for i, host := range hosts {
		shuffled[perm[i]] = host
	}

	return shuffled
}

func (c *controlConn) shuffleDial(endpoints []*HostInfo) (*Conn, error) {
	// shuffle endpoints so not all drivers will connect to the same initial
	// node.
	shuffled := shuffleHosts(endpoints)

	var err error
	for _, host := range shuffled {
		var conn *Conn
		conn, err = c.session.connect(host, c)
		if err == nil {
			return conn, nil
		}

		Logger.Printf("gocql: unable to dial control conn %v: %v\n", host.ConnectAddress(), err)
	}

	return nil, err
}

// this is going to be version dependant and a nightmare to maintain :(
var protocolSupportRe = regexp.MustCompile(`the lowest supported version is \d+ and the greatest is (\d+)$`)

func parseProtocolFromError(err error) int {
	// I really wish this had the actual info in the error frame...
	matches := protocolSupportRe.FindAllStringSubmatch(err.Error(), -1)
	if len(matches) != 1 || len(matches[0]) != 2 {
		if verr, ok := err.(*protocolError); ok {
			return int(verr.frame.Header().version.version())
		}
		return 0
	}

	max, err := strconv.Atoi(matches[0][1])
	if err != nil {
		return 0
	}

	return max
}

func (c *controlConn) discoverProtocol(hosts []*HostInfo) (int, error) {
	hosts = shuffleHosts(hosts)

	connCfg := *c.session.connCfg
	connCfg.ProtoVersion = 4 // TODO: define maxProtocol

	handler := connErrorHandlerFn(func(c *Conn, err error, closed bool) {
		// we should never get here, but if we do it means we connected to a
		// host successfully which means our attempted protocol version worked
		if !closed {
			c.Close()
		}
	})

	var err error
	for _, host := range hosts {
		var conn *Conn
		conn, err = c.session.dial(host.ConnectAddress(), host.Port(), &connCfg, handler)
		if conn != nil {
			conn.Close()
		}

		if err == nil {
			return connCfg.ProtoVersion, nil
		}

		if proto := parseProtocolFromError(err); proto > 0 {
			return proto, nil
		}
	}

	return 0, err
}

func (c *controlConn) connect(hosts []*HostInfo) error {
	if len(hosts) == 0 {
		return errors.New("control: no endpoints specified")
	}

	conn, err := c.shuffleDial(hosts)
	if err != nil {
		return fmt.Errorf("control: unable to connect to initial hosts: %v", err)
	}

	if err := c.setupConn(conn); err != nil {
		conn.Close()
		return fmt.Errorf("control: unable to setup connection: %v", err)
	}

	// we could fetch the initial ring here and update initial host data. So that
	// when we return from here we have a ring topology ready to go.

	go c.heartBeat()

	return nil
}

type connHost struct {
	conn *Conn
	host *HostInfo
}

func (c *controlConn) setupConn(conn *Conn) error {
	if err := c.registerEvents(conn); err != nil {
		conn.Close()
		return err
	}

	// TODO(zariel): do we need to fetch host info everytime
	// the control conn connects? Surely we have it cached?
	host, err := conn.localHostInfo()
	if err != nil {
		return err
	}

	ch := &connHost{
		conn: conn,
		host: host,
	}

	c.conn.Store(ch)
	// c.session.handleNodeUp(host.ConnectAddress(), host.Port(), false)

	return nil
}

func (c *controlConn) registerEvents(conn *Conn) error {
	var events []string

	if !c.session.cfg.Events.DisableTopologyEvents {
		events = append(events, "TOPOLOGY_CHANGE")
	}
	if !c.session.cfg.Events.DisableNodeStatusEvents {
		events = append(events, "STATUS_CHANGE")
	}
	if !c.session.cfg.Events.DisableSchemaEvents {
		events = append(events, "SCHEMA_CHANGE")
	}

	if len(events) == 0 {
		return nil
	}

	framer, err := conn.exec(context.Background(),
		&writeRegisterFrame{
			events: events,
		}, nil)
	if err != nil {
		return err
	}

	frame, err := framer.parseFrame()
	if err != nil {
		return err
	} else if _, ok := frame.(*readyFrame); !ok {
		return fmt.Errorf("unexpected frame in response to register: got %T: %v\n", frame, frame)
	}

	return nil
}

func (c *controlConn) reconnect(refreshring bool) {
	if !atomic.CompareAndSwapInt32(&c.reconnecting, 0, 1) {
		return
	}
	defer atomic.StoreInt32(&c.reconnecting, 0)
	// TODO: simplify this function, use session.ring to get hosts instead of the
	// connection pool

	var host *HostInfo
	ch := c.getConn()
	if ch != nil {
		host = ch.host
		ch.conn.Close()
	}

	var newConn *Conn
	if host != nil {
		// try to connect to the old host
		conn, err := c.session.connect(host, c)
		if err != nil {
			// host is dead
			// TODO: this is replicated in a few places
			c.session.handleNodeDown(host.ConnectAddress(), host.Port())
		} else {
			newConn = conn
		}
	}

	// TODO: should have our own round-robin for hosts so that we can try each
	// in succession and guarantee that we get a different host each time.
	if newConn == nil {
		host := c.session.ring.rrHost()
		if host == nil {
			c.connect(c.session.ring.endpoints)
			return
		}

		var err error
		newConn, err = c.session.connect(host, c)
		if err != nil {
			// TODO: add log handler for things like this
			return
		}
	}

	if err := c.setupConn(newConn); err != nil {
		newConn.Close()
		Logger.Printf("gocql: control unable to register events: %v\n", err)
		return
	}

	if refreshring {
		c.session.hostSource.refreshRing()
	}
}

func (c *controlConn) HandleError(conn *Conn, err error, closed bool) {
	if !closed {
		return
	}

	oldConn := c.getConn()
	if oldConn.conn != conn {
		return
	}

	c.reconnect(true)
}

func (c *controlConn) getConn() *connHost {
	return c.conn.Load().(*connHost)
}

func (c *controlConn) writeFrame(w frameWriter) (frame, error) {
	ch := c.getConn()
	if ch == nil {
		return nil, errNoControl
	}

	framer, err := ch.conn.exec(context.Background(), w, nil)
	if err != nil {
		return nil, err
	}

	return framer.parseFrame()
}

func (c *controlConn) withConnHost(fn func(*connHost) *Iter) *Iter {
	const maxConnectAttempts = 5
	connectAttempts := 0

	for i := 0; i < maxConnectAttempts; i++ {
		ch := c.getConn()
		if ch == nil {
			if connectAttempts > maxConnectAttempts {
				break
			}

			connectAttempts++

			c.reconnect(false)
			continue
		}

		return fn(ch)
	}

	return &Iter{err: errNoControl}
}

func (c *controlConn) withConn(fn func(*Conn) *Iter) *Iter {
	return c.withConnHost(func(ch *connHost) *Iter {
		return fn(ch.conn)
	})
}

// query will return nil if the connection is closed or nil
func (c *controlConn) query(statement string, values ...interface{}) (iter *Iter) {
	q := c.session.Query(statement, values...).Consistency(One).RoutingKey([]byte{}).Trace(nil)

	for {
		iter = c.withConn(func(conn *Conn) *Iter {
			return conn.executeQuery(q)
		})

		if gocqlDebug && iter.err != nil {
			Logger.Printf("control: error executing %q: %v\n", statement, iter.err)
		}

		q.attempts++
		if iter.err == nil || !c.retry.Attempt(q) {
			break
		}
	}

	return
}

func (c *controlConn) awaitSchemaAgreement() error {
	return c.withConn(func(conn *Conn) *Iter {
		return &Iter{err: conn.awaitSchemaAgreement()}
	}).err
}

func (c *controlConn) close() {
	if atomic.CompareAndSwapInt32(&c.started, 1, -1) {
		c.quit <- struct{}{}
	}

	ch := c.getConn()
	if ch != nil {
		ch.conn.Close()
	}
}

var errNoControl = errors.New("gocql: no control connection available")
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"fmt"
	"log"
	"net"
	"net/textproto"
	"strings"
)

// TCPServer simple tcp server for commands
func TCPServer() (ret int) {
	ln, err := net.Listen("tcp", ":"+TCPPort)
	if err != nil {
		log.Println("[control] error listening:", err.Error())
		return 1
	}
	log.Printf("[control] listening to port %s for connections...", TCPPort)
	defer ln.Close()

	for {
		conn, err := ln.Accept()
		bot := NewBot()
		bot.inconn = conn
		if err != nil {
			fmt.Println("[control] error accepting: ", err.Error())
			return 1
		}
		go handleRequest(conn, bot)
	}
}

func handleRequest(conn net.Conn, bot *Bot) {
	defer conn.Close()

	reader := bufio.NewReader(conn)
	tp := textproto.NewReader(reader)
	for {
		line, err := tp.ReadLine()

		if err != nil {
			fmt.Println("[control] read error:", err)
			fmt.Fprintf(conn, "[control] read error: %s", err)
			conn.Close()
			return
		}
		log.Println("[control] " + line)
		handleMessage(line, bot)
	}
}

// Handle an IRC received from a bot
func handleMessage(message string, bot *Bot) {
	remoteAddr := bot.inconn.RemoteAddr().String()
	remoteAddrIP := strings.Split(remoteAddr, ":")

	if strings.Contains(message, "JOIN ") {
		joinComm := strings.Split(message, "JOIN ")
		go bot.join(joinComm[1])
	} else if strings.Contains(message, "PASS ") {
		passComm := strings.Split(message, "PASS ")
		passwordParts := strings.Split(passComm[1], ";")
		if passwordParts[0] == TCPPass {
			bot.oauth = passwordParts[1]
			log.Printf("[control] authenticated! %s\n", remoteAddrIP)
		} else {
			log.Printf("[control] invalid broker pass! %s\n", remoteAddrIP)
			bot.inconn.Close()
			return
		}
	} else if strings.Contains(message, "NICK ") {
		nickComm := strings.Split(message, "NICK ")
		bot.nick = nickComm[1]

		if bot.oauth != "" {
			bot.CreateConnection()
			bot.CreateGroupConnection()
		}
	} else if strings.Contains(message, "USER ") {
		if bot.nick != "" {
			nickComm := strings.Split(message, "USER ")
			bot.nick = nickComm[1]

			if bot.oauth != "" {
				bot.CreateConnection()
				bot.CreateGroupConnection()
			}
		}
	} else if strings.Contains(message, "PRIVMSG #jtv :/w ") {
		privmsgComm := strings.Split(message, "PRIVMSG #jtv :")
		bot.Whisper(privmsgComm[1])
	} else {
		bot.Message(message)
	}
}
<commit_msg>modified goroutines to correctly use new connections<commit_after>package main

import (
	"bufio"
	"fmt"
	"log"
	"net"
	"net/textproto"
	"strings"
)

// TCPServer simple tcp server for commands
func TCPServer() (ret int) {
	ln, err := net.Listen("tcp", ":"+TCPPort)
	if err != nil {
		log.Println("[control] error listening:", err.Error())
		return 1
	}
	log.Printf("[control] listening to port %s for connections...", TCPPort)
	defer ln.Close()

	for {
		conn, err := ln.Accept()
		bot := NewBot()
		bot.inconn = conn
		if err != nil {
			fmt.Println("[control] error accepting: ", err.Error())
			return 1
		}
		go handleRequest(conn, bot)
	}
}

func handleRequest(conn net.Conn, bot *Bot) {
	defer conn.Close()

	reader := bufio.NewReader(conn)
	tp := textproto.NewReader(reader)
	for {
		line, err := tp.ReadLine()

		if err != nil {
			fmt.Println("[control] read error:", err)
			fmt.Fprintf(conn, "[control] read error: %s", err)
			conn.Close()
			return
		}
		log.Println("[control] " + line)
		handleMessage(line, bot)
	}
}

// Handle an IRC received from a bot
func handleMessage(message string, bot *Bot) {
	remoteAddr := bot.inconn.RemoteAddr().String()
	remoteAddrIP := strings.Split(remoteAddr, ":")

	if strings.Contains(message, "JOIN ") {
		joinComm := strings.Split(message, "JOIN ")
		go bot.join(joinComm[1])
	} else if strings.Contains(message, "PASS ") {
		passComm := strings.Split(message, "PASS ")
		passwordParts := strings.Split(passComm[1], ";")
		if passwordParts[0] == TCPPass {
			bot.oauth = passwordParts[1]
			log.Printf("[control] authenticated! %s\n", remoteAddrIP)
		} else {
			log.Printf("[control] invalid broker pass! %s\n", remoteAddrIP)
			bot.inconn.Close()
			return
		}
	} else if strings.Contains(message, "NICK ") {
		nickComm := strings.Split(message, "NICK ")
		bot.nick = nickComm[1]

		if bot.oauth != "" {
			bot.CreateConnection()
			go bot.CreateGroupConnection()
		}
	} else if strings.Contains(message, "USER ") {
		if bot.nick != "" {
			nickComm := strings.Split(message, "USER ")
			bot.nick = nickComm[1]

			if bot.oauth != "" {
				bot.CreateConnection()
				go bot.CreateGroupConnection()
			}
		}
	} else if strings.Contains(message, "PRIVMSG #jtv :/w ") {
		privmsgComm := strings.Split(message, "PRIVMSG #jtv :")
		go bot.Whisper(privmsgComm[1])
	} else {
		bot.Message(message)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
)

// HelpForShow outputs usage information for the show commands: show, show-vm, show-group, show-account.
func (cmds *CommandSet) HelpForShow() {
	fmt.Println("go-bigv show")
	fmt.Println()
	fmt.Println("usage: go-bigv show [--json] <name>")
	fmt.Println("       go-bigv show vm [--json] <virtual machine>")
	fmt.Println("       go-bigv show group [--json] [--verbose] <group>")
	fmt.Println("       go-bigv show account [--json] [--verbose] <account>")
	fmt.Println()
	fmt.Println("Displays information about the given virtual machine, group, or account.")
	fmt.Println("If the --verbose flag is given to bigv show group or bigv show account, full details are given for each VM.")
	fmt.Println()
}

// ShowVM implements the show-vm command, which is used to display information about BigV VMs. See HelpForShow for the usage information.
func (cmds *CommandSet) ShowVM(args []string) {
	flags := MakeCommonFlagSet()
	jsonOut := flags.Bool("json", false, "")
	flags.Parse(args)
	args = cmds.config.ImportFlags(flags)

	cmds.EnsureAuth()

	name := cmds.bigv.ParseVirtualMachineName(args[0])

	vm, err := cmds.bigv.GetVirtualMachine(name)

	if err != nil {
		exit(err)
	}
	if !cmds.config.GetBool("silent") {
		if *jsonOut {
			fmt.Println(json.MarshalIndent(vm, "", "    "))
		} else {
			fmt.Println(FormatVirtualMachine(vm))
		}
	}

}

// ShowAccount implements the show-account command, which is used to show the BigV account name, as well as the groups and VMs within it.
func (cmds *CommandSet) ShowAccount(args []string) {
	flags := MakeCommonFlagSet()
	jsonOut := flags.Bool("json", false, "")
	flags.Parse(args)
	args = cmds.config.ImportFlags(flags)

	name := cmds.bigv.ParseAccountName(args[0])

	acc, err := cmds.bigv.GetAccount(name)

	if err != nil {
		exit(err)
	}

	if *jsonOut {
		fmt.Println(json.MarshalIndent(acc, "", "    "))
	} else {
		fmt.Printf("Account %d: %s", acc.ID, acc.Name)
	}

}
<commit_msg>Fix JSON output for the show-vm and show-account commands.<commit_after>package main

import (
	"encoding/json"
	"fmt"
)

// HelpForShow outputs usage information for the show commands: show, show-vm, show-group, show-account.
func (cmds *CommandSet) HelpForShow() {
	fmt.Println("go-bigv show")
	fmt.Println()
	fmt.Println("usage: go-bigv show [--json] <name>")
	fmt.Println("       go-bigv show vm [--json] <virtual machine>")
	fmt.Println("       go-bigv show group [--json] [--verbose] <group>")
	fmt.Println("       go-bigv show account [--json] [--verbose] <account>")
	fmt.Println()
	fmt.Println("Displays information about the given virtual machine, group, or account.")
	fmt.Println("If the --verbose flag is given to bigv show group or bigv show account, full details are given for each VM.")
	fmt.Println()
}

// ShowVM implements the show-vm command, which is used to display information about BigV VMs. See HelpForShow for the usage information.
func (cmds *CommandSet) ShowVM(args []string) {
	flags := MakeCommonFlagSet()
	jsonOut := flags.Bool("json", false, "")
	flags.Parse(args)
	args = cmds.config.ImportFlags(flags)

	cmds.EnsureAuth()

	name := cmds.bigv.ParseVirtualMachineName(args[0])

	vm, err := cmds.bigv.GetVirtualMachine(name)

	if err != nil {
		exit(err)
	}
	if !cmds.config.GetBool("silent") {
		if *jsonOut {
			js, _ := json.MarshalIndent(vm, "", "    ")
			fmt.Println(string(js))
		} else {
			fmt.Println(FormatVirtualMachine(vm))
		}
	}

}

// ShowAccount implements the show-account command, which is used to show the BigV account name, as well as the groups and VMs within it.
func (cmds *CommandSet) ShowAccount(args []string) {
	flags := MakeCommonFlagSet()
	jsonOut := flags.Bool("json", false, "")
	flags.Parse(args)
	args = cmds.config.ImportFlags(flags)

	name := cmds.bigv.ParseAccountName(args[0])

	acc, err := cmds.bigv.GetAccount(name)

	if err != nil {
		exit(err)
	}

	if *jsonOut {
		js, _ := json.MarshalIndent(acc, "", "    ")
		fmt.Println(string(js))
	} else {
		fmt.Printf("Account %d: %s", acc.ID, acc.Name)
	}

}
<|endoftext|>


<commit_before>// Copyright 2011 Arne Roomann-Kurrik.
//
// 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 oauth1a implements the OAuth 1.0a specification.
*/
package oauth1a

import (
	"bytes"
	"crypto/hmac"
	"crypto/rand"
	"crypto/sha1"
	"encoding/base64"
	"encoding/hex"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"sort"
	"strings"
	"time"
)

// Container for client-specific configuration related to the OAuth process.
// This struct is intended to be serialized and stored for future use.
type ClientConfig struct {
	ConsumerSecret string
	ConsumerKey    string
	CallbackURL    string
}

// Represents an API which offers OAuth access.
type Service struct {
	RequestURL   string
	AuthorizeURL string
	AccessURL    string
	*ClientConfig
	Signer
}

// Signs an HTTP request with the needed OAuth parameters.
func (s *Service) Sign(request *http.Request, userConfig *UserConfig) error {
	return s.Signer.Sign(request, s.ClientConfig, userConfig)
}

// Interface for any OAuth signing implementations.
type Signer interface {
	Sign(request *http.Request, config *ClientConfig, user *UserConfig) error
}

// A Signer which implements the HMAC-SHA1 signing algorithm.
type HmacSha1Signer struct{}

// Generate a unique nonce value.
func (HmacSha1Signer) generateNonce() string {
	nonce := make([]byte, 16)
	_, err := io.ReadFull(rand.Reader, nonce)
	if err != nil {
		panic("unable to read from crypto/rand.Reader; process is insecure: " + err.Error())
	}
	return hex.EncodeToString(nonce)
}

// Generate a timestamp.
func (HmacSha1Signer) generateTimestamp() int64 {
	return time.Now().UTC().Unix()
}

// Returns a map of all of the oauth_* (including signature) parameters for the
// given request, and the signature base string used to generate the signature.
func (s *HmacSha1Signer) GetOAuthParams(request *http.Request, clientConfig *ClientConfig, userConfig *UserConfig, nonce string, timestamp string) (map[string]string, string) {
	oauthParams := map[string]string{
		"oauth_consumer_key":     clientConfig.ConsumerKey,
		"oauth_nonce":            nonce,
		"oauth_signature_method": "HMAC-SHA1",
		"oauth_timestamp":        timestamp,
		"oauth_version":          "1.0",
	}
	tokenKey, tokenSecret := userConfig.GetToken()
	if tokenKey != "" {
		oauthParams["oauth_token"] = tokenKey
	}

	signingParams := request.URL.Query()
	for key, value := range oauthParams {
		signingParams.Set(key, value)
	}

	if request.Body != nil && request.Header.Get("Content-Type") == "application/x-www-form-urlencoded" {
		request.ParseForm()
		for key, values := range request.Form {
			for _, v := range values {
				signingParams.Add(key, v)
			}
		}
		// Calling ParseForm clears out the reader.  It may be
		// necessary to do this in a less destructive way, but for
		// right now, this code reinitializes the body of the request.
		body := strings.NewReader(request.Form.Encode())
		request.Body = ioutil.NopCloser(body)
		request.ContentLength = int64(body.Len())
	}

	signingUrl := fmt.Sprintf("%v://%v%v", request.URL.Scheme, request.URL.Host, request.URL.Path)
	signatureParts := []string{
		request.Method,
		url.QueryEscape(signingUrl),
		url.QueryEscape(sortedQueryString(signingParams))}
	signatureBase := strings.Join(signatureParts, "&")
	oauthParams["oauth_signature"] = s.GetSignature(clientConfig.ConsumerSecret, tokenSecret, signatureBase)
	return oauthParams, signatureBase
}

// Calculates the HMAC-SHA1 signature of a base string, given a consumer and
// token secret.
func (s *HmacSha1Signer) GetSignature(consumerSecret string, tokenSecret string, signatureBase string) string {
	signingKey := consumerSecret + "&" + tokenSecret
	signer := hmac.New(sha1.New, []byte(signingKey))
	signer.Write([]byte(signatureBase))
	oauthSignature := base64.StdEncoding.EncodeToString(signer.Sum(nil))
	return oauthSignature
}

// Given an unsigned request, add the appropriate OAuth Authorization header
// using the HMAC-SHA1 algorithm.
func (s *HmacSha1Signer) Sign(request *http.Request, clientConfig *ClientConfig, userConfig *UserConfig) error {
	var (
		nonce     string
		timestamp string
	)
	if nonce = request.Header.Get("X-OAuth-Nonce"); nonce != "" {
		request.Header.Del("X-OAuth-Nonce")
	} else {
		nonce = s.generateNonce()
	}
	if timestamp = request.Header.Get("X-OAuth-Timestamp"); timestamp != "" {
		request.Header.Del("X-OAuth-Timestamp")
	} else {
		timestamp = fmt.Sprintf("%v", s.generateTimestamp())
	}
	oauthParams, _ := s.GetOAuthParams(request, clientConfig, userConfig, nonce, timestamp)

	headerParts := make([]string, 0, len(oauthParams))
	for key, value := range oauthParams {
		val := Rfc3986Escape(key) + "=\"" + Rfc3986Escape(value) + "\""
		headerParts = append(headerParts, val)
	}
	sort.Strings(headerParts)
	oauthHeader := "OAuth " + strings.Join(headerParts, ", ")
	request.Header["Authorization"] = []string{oauthHeader}

	request.URL.RawQuery = sortedQueryString(request.URL.Query())
	return nil
}

// This bit of fussing is because '/' is not encoded correctly
// by the URL package, so we encode manually.
func sortedQueryString(values url.Values) string {
	if len(values) == 0 {
		return ""
	}
	pairs := make(sortedPairs, 0)
	for k, vs := range values {
		escK := Rfc3986Escape(k)
		for _, v := range vs {
			pairs = append(pairs, pair{escK, Rfc3986Escape(v)})
		}
	}
	sort.Sort(pairs)

	buf := new(bytes.Buffer)
	buf.WriteString(pairs[0].k)
	buf.WriteByte('=')
	buf.WriteString(pairs[0].v)

	for _, p := range pairs[1:] {
		buf.WriteByte('&')
		buf.WriteString(p.k)
		buf.WriteByte('=')
		buf.WriteString(p.v)
	}
	return buf.String()
}

type pair struct{ k, v string }
type sortedPairs []pair

func (sp sortedPairs) Len() int {
	return len(sp)
}
func (p sortedPairs) Swap(i, j int) {
	p[i], p[j] = p[j], p[i]
}

func (p sortedPairs) Less(i, j int) bool {
	if p[i].k == p[j].k {
		return p[i].v < p[j].v
	}
	return p[i].k < p[j].k
}

// Escapes a string more in line with Rfc3986 than http.URLEscape.
// URLEscape was converting spaces to "+" instead of "%20", which was messing up
// the signing of requests.
func Rfc3986Escape(input string) string {
	firstEsc := -1
	b := []byte(input)
	for i, c := range b {
		if !isSafeChar(c) {
			firstEsc = i
			break
		}
	}

	// If nothing needed to be escaped, then the input is clean and
	// we're done.
	if firstEsc == -1 {
		return input
	}

	// If something did need to be escaped, write the prefix that was
	// fine to the buffer and iterate through the rest of the bytes.
	output := new(bytes.Buffer)
	output.Write(b[:firstEsc])

	for _, c := range b[firstEsc:] {
		if isSafeChar(c) {
			output.WriteByte(c)
		} else {
			fmt.Fprintf(output, "%%%02X", c)
		}
	}
	return output.String()
}

func isSafeChar(c byte) bool {
	return ('0' <= c && c <= '9') ||
		('a' <= c && c <= 'z') ||
		('A' <= c && c <= 'Z') ||
		c == '-' || c == '.' || c == '_' || c == '~'
}
<commit_msg>Escaping secrets used in signing.<commit_after>// Copyright 2011 Arne Roomann-Kurrik.
//
// 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 oauth1a implements the OAuth 1.0a specification.
*/
package oauth1a

import (
	"bytes"
	"crypto/hmac"
	"crypto/rand"
	"crypto/sha1"
	"encoding/base64"
	"encoding/hex"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"sort"
	"strings"
	"time"
)

// Container for client-specific configuration related to the OAuth process.
// This struct is intended to be serialized and stored for future use.
type ClientConfig struct {
	ConsumerSecret string
	ConsumerKey    string
	CallbackURL    string
}

// Represents an API which offers OAuth access.
type Service struct {
	RequestURL   string
	AuthorizeURL string
	AccessURL    string
	*ClientConfig
	Signer
}

// Signs an HTTP request with the needed OAuth parameters.
func (s *Service) Sign(request *http.Request, userConfig *UserConfig) error {
	return s.Signer.Sign(request, s.ClientConfig, userConfig)
}

// Interface for any OAuth signing implementations.
type Signer interface {
	Sign(request *http.Request, config *ClientConfig, user *UserConfig) error
}

// A Signer which implements the HMAC-SHA1 signing algorithm.
type HmacSha1Signer struct{}

// Generate a unique nonce value.
func (HmacSha1Signer) generateNonce() string {
	nonce := make([]byte, 16)
	_, err := io.ReadFull(rand.Reader, nonce)
	if err != nil {
		panic("unable to read from crypto/rand.Reader; process is insecure: " + err.Error())
	}
	return hex.EncodeToString(nonce)
}

// Generate a timestamp.
func (HmacSha1Signer) generateTimestamp() int64 {
	return time.Now().UTC().Unix()
}

// Returns a map of all of the oauth_* (including signature) parameters for the
// given request, and the signature base string used to generate the signature.
func (s *HmacSha1Signer) GetOAuthParams(request *http.Request, clientConfig *ClientConfig, userConfig *UserConfig, nonce string, timestamp string) (map[string]string, string) {
	oauthParams := map[string]string{
		"oauth_consumer_key":     clientConfig.ConsumerKey,
		"oauth_nonce":            nonce,
		"oauth_signature_method": "HMAC-SHA1",
		"oauth_timestamp":        timestamp,
		"oauth_version":          "1.0",
	}
	tokenKey, tokenSecret := userConfig.GetToken()
	if tokenKey != "" {
		oauthParams["oauth_token"] = tokenKey
	}

	signingParams := request.URL.Query()
	for key, value := range oauthParams {
		signingParams.Set(key, value)
	}

	if request.Body != nil && request.Header.Get("Content-Type") == "application/x-www-form-urlencoded" {
		request.ParseForm()
		for key, values := range request.Form {
			for _, v := range values {
				signingParams.Add(key, v)
			}
		}
		// Calling ParseForm clears out the reader.  It may be
		// necessary to do this in a less destructive way, but for
		// right now, this code reinitializes the body of the request.
		body := strings.NewReader(request.Form.Encode())
		request.Body = ioutil.NopCloser(body)
		request.ContentLength = int64(body.Len())
	}

	signingUrl := fmt.Sprintf("%v://%v%v", request.URL.Scheme, request.URL.Host, request.URL.Path)
	signatureParts := []string{
		request.Method,
		url.QueryEscape(signingUrl),
		url.QueryEscape(sortedQueryString(signingParams))}
	signatureBase := strings.Join(signatureParts, "&")
	oauthParams["oauth_signature"] = s.GetSignature(clientConfig.ConsumerSecret, tokenSecret, signatureBase)
	return oauthParams, signatureBase
}

// Calculates the HMAC-SHA1 signature of a base string, given a consumer and
// token secret.
func (s *HmacSha1Signer) GetSignature(consumerSecret string, tokenSecret string, signatureBase string) string {
	signingKey := Rfc3986Escape(consumerSecret) + "&" + Rfc3986Escape(tokenSecret)
	signer := hmac.New(sha1.New, []byte(signingKey))
	signer.Write([]byte(signatureBase))
	oauthSignature := base64.StdEncoding.EncodeToString(signer.Sum(nil))
	return oauthSignature
}

// Given an unsigned request, add the appropriate OAuth Authorization header
// using the HMAC-SHA1 algorithm.
func (s *HmacSha1Signer) Sign(request *http.Request, clientConfig *ClientConfig, userConfig *UserConfig) error {
	var (
		nonce     string
		timestamp string
	)
	if nonce = request.Header.Get("X-OAuth-Nonce"); nonce != "" {
		request.Header.Del("X-OAuth-Nonce")
	} else {
		nonce = s.generateNonce()
	}
	if timestamp = request.Header.Get("X-OAuth-Timestamp"); timestamp != "" {
		request.Header.Del("X-OAuth-Timestamp")
	} else {
		timestamp = fmt.Sprintf("%v", s.generateTimestamp())
	}
	oauthParams, _ := s.GetOAuthParams(request, clientConfig, userConfig, nonce, timestamp)

	headerParts := make([]string, 0, len(oauthParams))
	for key, value := range oauthParams {
		val := Rfc3986Escape(key) + "=\"" + Rfc3986Escape(value) + "\""
		headerParts = append(headerParts, val)
	}
	sort.Strings(headerParts)
	oauthHeader := "OAuth " + strings.Join(headerParts, ", ")
	request.Header["Authorization"] = []string{oauthHeader}

	request.URL.RawQuery = sortedQueryString(request.URL.Query())
	return nil
}

// This bit of fussing is because '/' is not encoded correctly
// by the URL package, so we encode manually.
func sortedQueryString(values url.Values) string {
	if len(values) == 0 {
		return ""
	}
	pairs := make(sortedPairs, 0)
	for k, vs := range values {
		escK := Rfc3986Escape(k)
		for _, v := range vs {
			pairs = append(pairs, pair{escK, Rfc3986Escape(v)})
		}
	}
	sort.Sort(pairs)

	buf := new(bytes.Buffer)
	buf.WriteString(pairs[0].k)
	buf.WriteByte('=')
	buf.WriteString(pairs[0].v)

	for _, p := range pairs[1:] {
		buf.WriteByte('&')
		buf.WriteString(p.k)
		buf.WriteByte('=')
		buf.WriteString(p.v)
	}
	return buf.String()
}

type pair struct{ k, v string }
type sortedPairs []pair

func (sp sortedPairs) Len() int {
	return len(sp)
}
func (p sortedPairs) Swap(i, j int) {
	p[i], p[j] = p[j], p[i]
}

func (p sortedPairs) Less(i, j int) bool {
	if p[i].k == p[j].k {
		return p[i].v < p[j].v
	}
	return p[i].k < p[j].k
}

// Escapes a string more in line with Rfc3986 than http.URLEscape.
// URLEscape was converting spaces to "+" instead of "%20", which was messing up
// the signing of requests.
func Rfc3986Escape(input string) string {
	firstEsc := -1
	b := []byte(input)
	for i, c := range b {
		if !isSafeChar(c) {
			firstEsc = i
			break
		}
	}

	// If nothing needed to be escaped, then the input is clean and
	// we're done.
	if firstEsc == -1 {
		return input
	}

	// If something did need to be escaped, write the prefix that was
	// fine to the buffer and iterate through the rest of the bytes.
	output := new(bytes.Buffer)
	output.Write(b[:firstEsc])

	for _, c := range b[firstEsc:] {
		if isSafeChar(c) {
			output.WriteByte(c)
		} else {
			fmt.Fprintf(output, "%%%02X", c)
		}
	}
	return output.String()
}

func isSafeChar(c byte) bool {
	return ('0' <= c && c <= '9') ||
		('a' <= c && c <= 'z') ||
		('A' <= c && c <= 'Z') ||
		c == '-' || c == '.' || c == '_' || c == '~'
}
<|endoftext|>


<commit_before>package kcp

import (
	"container/heap"
	"sync"
	"time"
)

var updater updateHeap

func init() {
	updater.init()
	go updater.updateTask()
}

// entry contains a session update info
type entry struct {
	ts time.Time
	s  *UDPSession
}

// a global heap managed kcp.flush() caller
type updateHeap struct {
	entries  []entry
	mu       sync.Mutex
	chWakeUp chan struct{}
}

func (h *updateHeap) Len() int           { return len(h.entries) }
func (h *updateHeap) Less(i, j int) bool { return h.entries[i].ts.Before(h.entries[j].ts) }
func (h *updateHeap) Swap(i, j int) {
	h.entries[i], h.entries[j] = h.entries[j], h.entries[i]
	h.entries[i].s.updaterIdx = i
	h.entries[j].s.updaterIdx = j
}

func (h *updateHeap) Push(x interface{}) {
	h.entries = append(h.entries, x.(entry))
	n := len(h.entries)
	h.entries[n-1].s.updaterIdx = n - 1
}

func (h *updateHeap) Pop() interface{} {
	n := len(h.entries)
	x := h.entries[n-1]
	h.entries[n-1].s.updaterIdx = -1
	h.entries[n-1] = entry{} // manual set nil for GC
	h.entries = h.entries[0 : n-1]
	return x
}

func (h *updateHeap) init() {
	h.chWakeUp = make(chan struct{}, 1)
}

func (h *updateHeap) addSession(s *UDPSession) {
	h.mu.Lock()
	heap.Push(h, entry{time.Now(), s})
	h.mu.Unlock()
	h.wakeup()
}

func (h *updateHeap) removeSession(s *UDPSession) {
	h.mu.Lock()
	if s.updaterIdx != -1 {
		heap.Remove(h, s.updaterIdx)
	}
	h.mu.Unlock()
}

func (h *updateHeap) wakeup() {
	select {
	case h.chWakeUp <- struct{}{}:
	default:
	}
}

func (h *updateHeap) updateTask() {
	var timer <-chan time.Time
	for {
		select {
		case <-timer:
		case <-h.chWakeUp:
		}

		h.mu.Lock()
		hlen := h.Len()
		for i := 0; i < hlen; i++ {
			entry := &h.entries[0]
			if time.Now().After(entry.ts) {
				interval := entry.s.update()
				entry.ts = time.Now().Add(interval)
				heap.Fix(h, 0)
			} else {
				break
			}
		}

		if hlen > 0 {
			timer = time.After(h.entries[0].ts.Sub(time.Now()))
		}
		h.mu.Unlock()
	}
}
<commit_msg>reuse time.Timer object instead of creating repeatedly<commit_after>package kcp

import (
	"container/heap"
	"sync"
	"time"
)

var updater updateHeap

func init() {
	updater.init()
	go updater.updateTask()
}

// entry contains a session update info
type entry struct {
	ts time.Time
	s  *UDPSession
}

// a global heap managed kcp.flush() caller
type updateHeap struct {
	entries  []entry
	mu       sync.Mutex
	chWakeUp chan struct{}
}

func (h *updateHeap) Len() int           { return len(h.entries) }
func (h *updateHeap) Less(i, j int) bool { return h.entries[i].ts.Before(h.entries[j].ts) }
func (h *updateHeap) Swap(i, j int) {
	h.entries[i], h.entries[j] = h.entries[j], h.entries[i]
	h.entries[i].s.updaterIdx = i
	h.entries[j].s.updaterIdx = j
}

func (h *updateHeap) Push(x interface{}) {
	h.entries = append(h.entries, x.(entry))
	n := len(h.entries)
	h.entries[n-1].s.updaterIdx = n - 1
}

func (h *updateHeap) Pop() interface{} {
	n := len(h.entries)
	x := h.entries[n-1]
	h.entries[n-1].s.updaterIdx = -1
	h.entries[n-1] = entry{} // manual set nil for GC
	h.entries = h.entries[0 : n-1]
	return x
}

func (h *updateHeap) init() {
	h.chWakeUp = make(chan struct{}, 1)
}

func (h *updateHeap) addSession(s *UDPSession) {
	h.mu.Lock()
	heap.Push(h, entry{time.Now(), s})
	h.mu.Unlock()
	h.wakeup()
}

func (h *updateHeap) removeSession(s *UDPSession) {
	h.mu.Lock()
	if s.updaterIdx != -1 {
		heap.Remove(h, s.updaterIdx)
	}
	h.mu.Unlock()
}

func (h *updateHeap) wakeup() {
	select {
	case h.chWakeUp <- struct{}{}:
	default:
	}
}

func (h *updateHeap) updateTask() {
	timer := time.NewTimer(0)
	for {
		select {
		case <-timer.C:
		case <-h.chWakeUp:
		}

		h.mu.Lock()
		hlen := h.Len()
		for i := 0; i < hlen; i++ {
			entry := &h.entries[0]
			if time.Now().After(entry.ts) {
				interval := entry.s.update()
				entry.ts = time.Now().Add(interval)
				heap.Fix(h, 0)
			} else {
				break
			}
		}

		if hlen > 0 {
			timer.Reset(h.entries[0].ts.Sub(time.Now()))
		}
		h.mu.Unlock()
	}
}
<|endoftext|>


<commit_before>package handler

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

	"github.com/gorilla/mux"

	"github.com/gilcrest/errs"
	"github.com/gilcrest/go-api-basic/controller/movieController"
)

// AddMovie handles POST requests for the /movies endpoint
// and creates a movie in the database
func (ah *AppHandler) AddMovie(w http.ResponseWriter, r *http.Request) {
	const op errs.Op = "handler/AppHandler.AddMovie"

	logger := ah.App.Logger
	logger.Debug().Msgf("START %s", op)
	defer logger.Debug().Msgf("END %s", op)

	// retrieve the context from the http.Request
	ctx := r.Context()

	// retrieve the user from the request Context
	token, err := accessToken(ctx)
	if err != nil {
		errs.HTTPErrorResponse(w, logger, errs.E(op, err))
		return
	}

	// Declare requestData as an instance of movieController.RequestData
	requestData := new(movieController.RequestData)

	// Decode JSON HTTP request body into a Decoder type
	// and unmarshal that into the MovieRequest struct in the
	// AddMovieHandler
	err = json.NewDecoder(r.Body).Decode(&requestData)
	defer r.Body.Close()
	// Call DecoderErr to determine if body is nil, json is malformed
	// or any other error
	err = DecoderErr(err)
	if err != nil {
		errs.HTTPErrorResponse(w, logger, errs.E(op, err))
		return
	}

	// Initialize the MovieController
	mc := movieController.NewMovieController(ah.App, ah.StandardResponseFields)

	// Send the request context and request struct to the controller
	// Receive a response or error in return
	response, err := mc.AddMovie(ctx, requestData, token)
	if err != nil {
		errs.HTTPErrorResponse(w, logger, errs.E(op, err))
		return
	}

	// Encode response struct to JSON for the response body
	err = json.NewEncoder(w).Encode(*response)
	if err != nil {
		errs.HTTPErrorResponse(w, logger, errs.E(op, errs.Internal, err))
		return
	}
}

// UpdateMovie handles PUT requests for the /movies/{id} endpoint
// and updates the given movie
func (ah *AppHandler) UpdateMovie(w http.ResponseWriter, r *http.Request) {
	const op errs.Op = "handler/AppHandler.Update"

	logger := ah.App.Logger
	logger.Debug().Msgf("START %s", op)
	defer logger.Debug().Msgf("END %s", op)

	// retrieve the context from the http.Request
	ctx := r.Context()

	// retrieve the user from the request Context
	token, err := accessToken(ctx)
	if err != nil {
		errs.HTTPErrorResponse(w, logger, errs.E(op, err))
		return
	}

	// gorilla mux Vars function returns the route variables for the
	// current request, if any. id is the external id given for the
	// movie
	vars := mux.Vars(r)
	id := vars["id"]

	// Declare requestData as an instance of movieController.RequestData
	requestData := new(movieController.RequestData)

	// Decode JSON HTTP request body into a Decoder type
	// and unmarshal that into requestData
	err = json.NewDecoder(r.Body).Decode(&requestData)
	defer r.Body.Close()
	// Call DecoderErr to determine if body is nil, json is malformed
	// or any other error
	err = DecoderErr(err)
	if err != nil {
		errs.HTTPErrorResponse(w, logger, errs.E(op, err))
		return
	}

	// Initialize the MovieController
	mc := movieController.NewMovieController(ah.App, ah.StandardResponseFields)

	// Send the request context and request struct to the controller
	// Receive a response or error in return
	resp, err := mc.Update(ctx, id, requestData, token)
	if err != nil {
		errs.HTTPErrorResponse(w, logger, errs.E(op, err))
		return
	}

	// Encode response struct to JSON for the response body
	err = json.NewEncoder(w).Encode(resp)
	if err != nil {
		errs.HTTPErrorResponse(w, logger, errs.E(op, errs.Internal, err))
		return
	}
}

//// FindByID handles GET requests for the /movies/{id} endpoint
//// and finds a movie by it's ID
//func (ah *AppHandler) FindByID(w http.ResponseWriter, r *http.Request) {
//	const op errs.Op = "handler/AppHandler.FindByID"
//
//	vars := mux.Vars(r)
//	id := vars["id"]
//
//	// retrieve the context from the http.Request
//	ctx := r.Context()
//
//	// Initialize the MovieController
//	mc := movieController.NewMovieController(ah.App, ah.StandardResponseFields)
//
//	// Send the request context and request struct to the controller
//	// Receive a response or error in return
//	resp, err := mc.FindByID(ctx, id)
//	if err != nil {
//		err = errs.RE(http.StatusBadRequest, errs.InvalidRequest, errs.E(op, err))
//		errs.HTTPError(w, err)
//		return
//	}
//
//	// Encode response struct to JSON for the response body
//	err = json.NewEncoder(w).Encode(resp)
//	if err != nil {
//		err = errs.RE(http.StatusInternalServerError, errs.E(op, errs.Internal))
//		errs.HTTPError(w, err)
//		return
//	}
//}
//
//// FindAll handles GET requests for the /movies endpoint
//// and finds all movies
//func (ah *AppHandler) FindAll(w http.ResponseWriter, r *http.Request) {
//	const op errs.Op = "handler/AppHandler.FindAll"
//
//	// retrieve the context from the http.Request
//	ctx := r.Context()
//
//	// Initialize the MovieController
//	mc := movieController.NewMovieController(ah.App, ah.StandardResponseFields)
//
//	// Send the request context and request struct to the controller
//	// Receive a response or error in return
//	resp, err := mc.FindAll(ctx)
//	if err != nil {
//		err = errs.RE(http.StatusBadRequest, errs.InvalidRequest, errs.E(op, err))
//		errs.HTTPError(w, err)
//		return
//	}
//
//	// Encode response struct to JSON for the response body
//	err = json.NewEncoder(w).Encode(resp)
//	if err != nil {
//		err = errs.RE(http.StatusInternalServerError, errs.E(op, errs.Internal))
//		errs.HTTPError(w, err)
//		return
//	}
//}
//

//// Delete handles DELETE requests for the /movies/{id} endpoint
//// and updates the given movie
//func (ah *AppHandler) Delete(w http.ResponseWriter, r *http.Request) {
//	const op errs.Op = "handler/AppHandler.Delete"
//
//	vars := mux.Vars(r)
//	id := vars["id"]
//
//	// retrieve the context from the http.Request
//	ctx := r.Context()
//
//	// Initialize the MovieController
//	mc := movieController.NewMovieController(ah.App, ah.StandardResponseFields)
//
//	// Send the request context and request struct to the controller
//	// Receive a response or error in return
//	resp, err := mc.Delete(ctx, id)
//	if err != nil {
//		err = errs.RE(http.StatusBadRequest, errs.InvalidRequest, errs.E(op, err))
//		errs.HTTPError(w, err)
//		return
//	}
//
//	// Encode response struct to JSON for the response body
//	err = json.NewEncoder(w).Encode(resp)
//	if err != nil {
//		err = errs.RE(http.StatusInternalServerError, errs.E(op, errs.Internal))
//		errs.HTTPError(w, err)
//		return
//	}
//}
<commit_msg>bring back delete and changes for errs<commit_after>package handler

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

	"github.com/gorilla/mux"

	"github.com/gilcrest/errs"
	"github.com/gilcrest/go-api-basic/controller/movieController"
)

// AddMovie handles POST requests for the /movies endpoint
// and creates a movie in the database
func (ah *AppHandler) AddMovie(w http.ResponseWriter, r *http.Request) {
	const op errs.Op = "handler/AppHandler.AddMovie"

	logger := ah.App.Logger
	logger.Debug().Msgf("START %s", op)
	defer logger.Debug().Msgf("END %s", op)

	// retrieve the context from the http.Request
	ctx := r.Context()

	// retrieve the user from the request Context
	token, err := accessToken(ctx)
	if err != nil {
		errs.HTTPErrorResponse(w, logger, errs.E(op, err))
		return
	}

	// Declare requestData as an instance of movieController.RequestData
	requestData := new(movieController.RequestData)

	// Decode JSON HTTP request body into a Decoder type
	// and unmarshal that into the MovieRequest struct in the
	// AddMovieHandler
	err = json.NewDecoder(r.Body).Decode(&requestData)
	defer r.Body.Close()
	// Call DecoderErr to determine if body is nil, json is malformed
	// or any other error
	err = DecoderErr(err)
	if err != nil {
		errs.HTTPErrorResponse(w, logger, errs.E(op, err))
		return
	}

	// Initialize the MovieController
	mc := movieController.NewMovieController(ah.App, ah.StandardResponseFields)

	// Send the request context and request struct to the controller
	// Receive a response or error in return
	response, err := mc.AddMovie(ctx, requestData, token)
	if err != nil {
		errs.HTTPErrorResponse(w, logger, errs.E(op, err))
		return
	}

	// Encode response struct to JSON for the response body
	err = json.NewEncoder(w).Encode(*response)
	if err != nil {
		errs.HTTPErrorResponse(w, logger, errs.E(op, errs.Internal, err))
		return
	}
}

// UpdateMovie handles PUT requests for the /movies/{id} endpoint
// and updates the given movie
func (ah *AppHandler) UpdateMovie(w http.ResponseWriter, r *http.Request) {
	const op errs.Op = "handler/AppHandler.Update"

	logger := ah.App.Logger
	logger.Debug().Msgf("START %s", op)
	defer logger.Debug().Msgf("END %s", op)

	// retrieve the context from the http.Request
	ctx := r.Context()

	// retrieve the user from the request Context
	token, err := accessToken(ctx)
	if err != nil {
		errs.HTTPErrorResponse(w, logger, errs.E(op, err))
		return
	}

	// gorilla mux Vars function returns the route variables for the
	// current request, if any. id is the external id given for the
	// movie
	vars := mux.Vars(r)
	id := vars["id"]

	// Declare requestData as an instance of movieController.RequestData
	requestData := new(movieController.RequestData)

	// Decode JSON HTTP request body into a Decoder type
	// and unmarshal that into requestData
	err = json.NewDecoder(r.Body).Decode(&requestData)
	defer r.Body.Close()
	// Call DecoderErr to determine if body is nil, json is malformed
	// or any other error
	err = DecoderErr(err)
	if err != nil {
		errs.HTTPErrorResponse(w, logger, errs.E(op, err))
		return
	}

	// Initialize the MovieController
	mc := movieController.NewMovieController(ah.App, ah.StandardResponseFields)

	// Send the request context and request struct to the controller
	// Receive a response or error in return
	resp, err := mc.Update(ctx, id, requestData, token)
	if err != nil {
		errs.HTTPErrorResponse(w, logger, errs.E(op, err))
		return
	}

	// Encode response struct to JSON for the response body
	err = json.NewEncoder(w).Encode(resp)
	if err != nil {
		errs.HTTPErrorResponse(w, logger, errs.E(op, errs.Internal, err))
		return
	}
}

// Delete handles DELETE requests for the /movies/{id} endpoint
// and updates the given movie
func (ah *AppHandler) Delete(w http.ResponseWriter, r *http.Request) {
	const op errs.Op = "handler/AppHandler.Delete"

	logger := ah.App.Logger
	logger.Debug().Msgf("START %s", op)
	defer logger.Debug().Msgf("END %s", op)

	// retrieve the context from the http.Request
	ctx := r.Context()

	// retrieve the user from the request Context
	token, err := accessToken(ctx)
	if err != nil {
		errs.HTTPErrorResponse(w, logger, errs.E(op, err))
		return
	}

	// gorilla mux Vars function returns the route variables for the
	// current request, if any. id is the external id given for the
	// movie
	vars := mux.Vars(r)
	id := vars["id"]

	// Initialize the MovieController
	mc := movieController.NewMovieController(ah.App, ah.StandardResponseFields)

	// Send the request context and request struct to the controller
	// Receive a response or error in return
	resp, err := mc.Delete(ctx, id, token)
	if err != nil {
		errs.HTTPErrorResponse(w, logger, errs.E(op, err))
		return
	}

	// Encode response struct to JSON for the response body
	err = json.NewEncoder(w).Encode(resp)
	if err != nil {
		errs.HTTPErrorResponse(w, logger, errs.E(op, errs.Internal, err))
		return
	}
}

//// FindByID handles GET requests for the /movies/{id} endpoint
//// and finds a movie by it's ID
//func (ah *AppHandler) FindByID(w http.ResponseWriter, r *http.Request) {
//	const op errs.Op = "handler/AppHandler.FindByID"
//
//	vars := mux.Vars(r)
//	id := vars["id"]
//
//	// retrieve the context from the http.Request
//	ctx := r.Context()
//
//	// Initialize the MovieController
//	mc := movieController.NewMovieController(ah.App, ah.StandardResponseFields)
//
//	// Send the request context and request struct to the controller
//	// Receive a response or error in return
//	resp, err := mc.FindByID(ctx, id)
//	if err != nil {
//		err = errs.RE(http.StatusBadRequest, errs.InvalidRequest, errs.E(op, err))
//		errs.HTTPError(w, err)
//		return
//	}
//
//	// Encode response struct to JSON for the response body
//	err = json.NewEncoder(w).Encode(resp)
//	if err != nil {
//		err = errs.RE(http.StatusInternalServerError, errs.E(op, errs.Internal))
//		errs.HTTPError(w, err)
//		return
//	}
//}
//
//// FindAll handles GET requests for the /movies endpoint
//// and finds all movies
//func (ah *AppHandler) FindAll(w http.ResponseWriter, r *http.Request) {
//	const op errs.Op = "handler/AppHandler.FindAll"
//
//	// retrieve the context from the http.Request
//	ctx := r.Context()
//
//	// Initialize the MovieController
//	mc := movieController.NewMovieController(ah.App, ah.StandardResponseFields)
//
//	// Send the request context and request struct to the controller
//	// Receive a response or error in return
//	resp, err := mc.FindAll(ctx)
//	if err != nil {
//		err = errs.RE(http.StatusBadRequest, errs.InvalidRequest, errs.E(op, err))
//		errs.HTTPError(w, err)
//		return
//	}
//
//	// Encode response struct to JSON for the response body
//	err = json.NewEncoder(w).Encode(resp)
//	if err != nil {
//		err = errs.RE(http.StatusInternalServerError, errs.E(op, errs.Internal))
//		errs.HTTPError(w, err)
//		return
//	}
//}
//
<|endoftext|>


<commit_before>package handlers

import (
	"errors"
	"fmt"
	"net/http"
	"strings"

	"appengine"
	"appengine/user"

	"code.google.com/p/xsrftoken"

	"github.com/icco/natnatnat/models"
	"github.com/pilu/traffic"
)

type TagData struct {
	Posts interface{}
	Tag   string
}

func TagHandler(w traffic.ResponseWriter, r *traffic.Request) {
	c := appengine.NewContext(r.Request)
	tag := r.Param("id")

	if tag == "" {
		http.Redirect(w, r.Request, "/tags", 301)
	}

	if tag != strings.ToLower(tag) {
		http.Redirect(w, r.Request, fmt.Sprintf("/tags/%s", strings.ToLower(tag)), 301)
	}

	isAlias, alias := models.GetAlias(tag)
	if isAlias {
		http.Redirect(w, r.Request, fmt.Sprintf("/tags/%s", alias), 301)
	}

	entries, err := models.PostsWithTag(c, tag)
	if err != nil {
		http.Error(w, err.Error(), 500)
		return
	}
	data := &TagData{Posts: entries, Tag: tag}
	w.Render("tag", data)
}

type TagsData struct {
	Tags map[string]int
}

func TagsHandler(w traffic.ResponseWriter, r *traffic.Request) {
	c := appengine.NewContext(r.Request)
	w.Render("tags", &TagsData{Tags: models.AllTags(c)})
}

type AliasData struct {
	Aliases map[string]string
	Xsrf    string
	IsAdmin bool
}

func TagAliasGetHandler(w traffic.ResponseWriter, r *traffic.Request) {
	c := appengine.NewContext(r.Request)
	u := user.Current(c)
	if u == nil {
		url, _ := user.LoginURL(c, "/aliases")
		http.Redirect(w, r.Request, url, 302)
		return
	} else {
		c.Infof("Logged in as: %s", u.String())
	}

	if u != nil && !user.IsAdmin(c) {
		http.Error(w, errors.New("Not a valid user.").Error(), 403)
		return
	} else {
		token := xsrftoken.Generate(models.GetFlagLogError(c, "SESSION_KEY"), u.String(), "/aliases")
		w.Render("aliases", &AliasData{
			Aliases: models.AliasMap(c),
			Xsrf:    token,
			IsAdmin: user.IsAdmin(c),
		})
		return
	}
}

func TagAliasPostHandler(w traffic.ResponseWriter, r *traffic.Request) {
	c := appengine.NewContext(r.Request)
	u := user.Current(c)
	if u == nil {
		url, _ := user.LoginURL(c, "/aliases")
		http.Redirect(w, r.Request, url, 302)
		return
	} else {
		c.Infof("Logged in as: %s", u.String())
	}

	if u != nil && !user.IsAdmin(c) {
		http.Error(w, errors.New("Not a valid user.").Error(), 403)
		return
	} else {
		err := r.ParseForm()
		if err != nil {
			c.Warningf("Couldn't parse form: %v", r)
		}
		xsrf := r.Request.FormValue("xsrf")
		from := r.Request.FormValue("name")
		to := r.Request.FormValue("tag")

		if xsrftoken.Valid(xsrf, models.GetFlagLogError(c, "SESSION_KEY"), u.String(), r.Request.URL.Path) {
			c.Infof("Valid Token!")
			a := models.NewAlias(from, to)
			err = a.Save(c)
			if err != nil {
				http.Error(w, err.Error(), 500)
				return
			}
		} else {
			c.Infof("Invalid Token...")
			http.Error(w, errors.New("Invalid Token").Error(), 403)
			return
		}

		http.Redirect(w, r.Request, "/aliases", 302)
		return
	}
}
<commit_msg>maybe<commit_after>package handlers

import (
	"errors"
	"fmt"
	"net/http"
	"strings"

	"appengine"
	"appengine/user"

	"code.google.com/p/xsrftoken"

	"github.com/icco/natnatnat/models"
	"github.com/pilu/traffic"
)

type TagData struct {
	Posts interface{}
	Tag   string
}

func TagHandler(w traffic.ResponseWriter, r *traffic.Request) {
	c := appengine.NewContext(r.Request)
	tag := r.Param("id")

	if tag == "" {
		http.Redirect(w, r.Request, "/tags", 301)
	}

	if tag != strings.ToLower(tag) {
		http.Redirect(w, r.Request, fmt.Sprintf("/tags/%s", strings.ToLower(tag)), 301)
	}

	isAlias, alias := models.GetAlias(c, tag)
	if isAlias {
		http.Redirect(w, r.Request, fmt.Sprintf("/tags/%s", alias), 301)
	}

	entries, err := models.PostsWithTag(c, tag)
	if err != nil {
		http.Error(w, err.Error(), 500)
		return
	}
	data := &TagData{Posts: entries, Tag: tag}
	w.Render("tag", data)
}

type TagsData struct {
	Tags map[string]int
}

func TagsHandler(w traffic.ResponseWriter, r *traffic.Request) {
	c := appengine.NewContext(r.Request)
	w.Render("tags", &TagsData{Tags: models.AllTags(c)})
}

type AliasData struct {
	Aliases map[string]string
	Xsrf    string
	IsAdmin bool
}

func TagAliasGetHandler(w traffic.ResponseWriter, r *traffic.Request) {
	c := appengine.NewContext(r.Request)
	u := user.Current(c)
	if u == nil {
		url, _ := user.LoginURL(c, "/aliases")
		http.Redirect(w, r.Request, url, 302)
		return
	} else {
		c.Infof("Logged in as: %s", u.String())
	}

	if u != nil && !user.IsAdmin(c) {
		http.Error(w, errors.New("Not a valid user.").Error(), 403)
		return
	} else {
		token := xsrftoken.Generate(models.GetFlagLogError(c, "SESSION_KEY"), u.String(), "/aliases")
		w.Render("aliases", &AliasData{
			Aliases: models.AliasMap(c),
			Xsrf:    token,
			IsAdmin: user.IsAdmin(c),
		})
		return
	}
}

func TagAliasPostHandler(w traffic.ResponseWriter, r *traffic.Request) {
	c := appengine.NewContext(r.Request)
	u := user.Current(c)
	if u == nil {
		url, _ := user.LoginURL(c, "/aliases")
		http.Redirect(w, r.Request, url, 302)
		return
	} else {
		c.Infof("Logged in as: %s", u.String())
	}

	if u != nil && !user.IsAdmin(c) {
		http.Error(w, errors.New("Not a valid user.").Error(), 403)
		return
	} else {
		err := r.ParseForm()
		if err != nil {
			c.Warningf("Couldn't parse form: %v", r)
		}
		xsrf := r.Request.FormValue("xsrf")
		from := r.Request.FormValue("name")
		to := r.Request.FormValue("tag")

		if xsrftoken.Valid(xsrf, models.GetFlagLogError(c, "SESSION_KEY"), u.String(), r.Request.URL.Path) {
			c.Infof("Valid Token!")
			a := models.NewAlias(from, to)
			err = a.Save(c)
			if err != nil {
				http.Error(w, err.Error(), 500)
				return
			}
		} else {
			c.Infof("Invalid Token...")
			http.Error(w, errors.New("Invalid Token").Error(), 403)
			return
		}

		http.Redirect(w, r.Request, "/aliases", 302)
		return
	}
}
<|endoftext|>


<commit_before>package handlers

import (
	"bufio"
	"net"
	"net/http"
)

type (
	TransparentResponseWriter struct {
		http.ResponseWriter
		Status int
	}
)

func (w *TransparentResponseWriter) WriteHeader(status int) {
	w.Status = status
	w.ResponseWriter.WriteHeader(status)
}

func (w *TransparentResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
	return w.ResponseWriter.(http.Hijacker).Hijack()
}

func (w *TransparentResponseWriter) Success() bool {
	return w.Status >= 200 && w.Status < 300
}
<commit_msg>handlers: add Size to TransparentResponseWriter<commit_after>package handlers

import (
	"bufio"
	"net"
	"net/http"
)

type (
	TransparentResponseWriter struct {
		http.ResponseWriter
		Status int
		Size   int
	}
)

func (w *TransparentResponseWriter) WriteHeader(status int) {
	w.Status = status
	w.ResponseWriter.WriteHeader(status)
}

func (w *TransparentResponseWriter) Write(data []byte) (int, error) {
	w.Size += len(data)
	return w.ResponseWriter.Write(data)
}

func (w *TransparentResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
	return w.ResponseWriter.(http.Hijacker).Hijack()
}

func (w *TransparentResponseWriter) Success() bool {
	return w.Status >= 200 && w.Status < 300
}
<|endoftext|>


<commit_before>package colonycore

import (
	"github.com/eaciit/orm/v1"
)

type Ldap struct {
	orm.ModelBase
	ID              string `json:"_id",bson:"_id"`
	Address         string
	BaseDN          string
	FilterUser      string
	FilterGroup     string
	Username        string
	Password        string
	AttributesUser  []string
	AttributesGroup []string
}

func (a *Ldap) TableName() string {
	return "ldap"
}

func (a *Ldap) RecordID() interface{} {
	return a.ID
}

func (a *Ldap) RecordID2() interface{} {
	return a.ID
}
<commit_msg>remove password<commit_after>package colonycore

import (
	"github.com/eaciit/orm/v1"
)

type Ldap struct {
	orm.ModelBase
	ID          string `json:"_id",bson:"_id"`
	Address     string
	BaseDN      string
	FilterUser  string
	FilterGroup string
	Username    string
	// Password        string
	AttributesUser  []string
	AttributesGroup []string
}

func (a *Ldap) TableName() string {
	return "ldap"
}

func (a *Ldap) RecordID() interface{} {
	return a.ID
}

func (a *Ldap) RecordID2() interface{} {
	return a.ID
}
<|endoftext|>


<commit_before>// Go support for leveled logs, analogous to https://code.google.com/p/google-glog/
//
// Copyright 2013 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.

// File I/O for logs.

package klog

import (
	"errors"
	"fmt"
	"os"
	"os/user"
	"path/filepath"
	"strings"
	"sync"
	"time"
)

// MaxSize is the maximum size of a log file in bytes.
var MaxSize uint64 = 1024 * 1024 * 1800

// logDirs lists the candidate directories for new log files.
var logDirs []string

func createLogDirs() {
	if logging.logDir != "" {
		logDirs = append(logDirs, logging.logDir)
	}
	logDirs = append(logDirs, os.TempDir())
}

var (
	pid      = os.Getpid()
	program  = filepath.Base(os.Args[0])
	host     = "unknownhost"
	userName = "unknownuser"
)

func init() {
	h, err := os.Hostname()
	if err == nil {
		host = shortHostname(h)
	}

	current, err := user.Current()
	if err == nil {
		userName = current.Username
	}

	// Sanitize userName since it may contain filepath separators on Windows.
	userName = strings.Replace(userName, `\`, "_", -1)
}

// shortHostname returns its argument, truncating at the first period.
// For instance, given "www.google.com" it returns "www".
func shortHostname(hostname string) string {
	if i := strings.Index(hostname, "."); i >= 0 {
		return hostname[:i]
	}
	return hostname
}

// logName returns a new log file name containing tag, with start time t, and
// the name for the symlink for tag.
func logName(tag string, t time.Time) (name, link string) {
	name = fmt.Sprintf("%s.%s.%s.log.%s.%04d%02d%02d-%02d%02d%02d.%d",
		program,
		host,
		userName,
		tag,
		t.Year(),
		t.Month(),
		t.Day(),
		t.Hour(),
		t.Minute(),
		t.Second(),
		pid)
	return name, program + "." + tag
}

var onceLogDirs sync.Once

// create creates a new log file and returns the file and its filename, which
// contains tag ("INFO", "FATAL", etc.) and t.  If the file is created
// successfully, create also attempts to update the symlink for that tag, ignoring
// errors.
// The startup argument indicates whether this is the initial startup of klog.
// If startup is true, existing files are opened for appending instead of truncated.
func create(tag string, t time.Time, startup bool) (f *os.File, filename string, err error) {
	if logging.logFile != "" {
		f, err := openOrCreate(logging.logFile, startup)
		if err == nil {
			return f, logging.logFile, nil
		}
		return nil, "", fmt.Errorf("log: unable to create log: %v", err)
	}
	onceLogDirs.Do(createLogDirs)
	if len(logDirs) == 0 {
		return nil, "", errors.New("log: no log dirs")
	}
	name, link := logName(tag, t)
	var lastErr error
	for _, dir := range logDirs {
		fname := filepath.Join(dir, name)
		f, err := openOrCreate(fname, startup)
		if err == nil {
			symlink := filepath.Join(dir, link)
			os.Remove(symlink)        // ignore err
			os.Symlink(name, symlink) // ignore err
			return f, fname, nil
		}
		lastErr = err
	}
	return nil, "", fmt.Errorf("log: cannot create log: %v", lastErr)
}

// The startup argument indicates whether this is the initial startup of klog.
// If startup is true, existing files are opened for appending instead of truncated.
func openOrCreate(name string, startup bool) (*os.File, error) {
	if startup {
		f, err := os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
		return f, err
	}
	f, err := os.Create(name)
	return f, err
}
<commit_msg>klog_file: workaround stdlib.user not supporting Nano Server<commit_after>// Go support for leveled logs, analogous to https://code.google.com/p/google-glog/
//
// Copyright 2013 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.

// File I/O for logs.

package klog

import (
	"errors"
	"fmt"
	"os"
	"os/user"
	"path/filepath"
	"runtime"
	"strings"
	"sync"
	"time"
)

// MaxSize is the maximum size of a log file in bytes.
var MaxSize uint64 = 1024 * 1024 * 1800

// logDirs lists the candidate directories for new log files.
var logDirs []string

func createLogDirs() {
	if logging.logDir != "" {
		logDirs = append(logDirs, logging.logDir)
	}
	logDirs = append(logDirs, os.TempDir())
}

var (
	pid      = os.Getpid()
	program  = filepath.Base(os.Args[0])
	host     = "unknownhost"
	userName = "unknownuser"
)

func init() {
	h, err := os.Hostname()
	if err == nil {
		host = shortHostname(h)
	}

	// On Windows, the Go 'user' package requires netapi32.dll.
	// This affects Windows Nano Server:
	//   https://github.com/golang/go/issues/21867
	// Fallback to using environment variables.
	if runtime.GOOS == "windows" {
		u := os.Getenv("USERNAME")
		if len(u) == 0 {
			return
		}
		// Sanitize the USERNAME since it may contain filepath separators.
		u = strings.Replace(u, `\`, "_", -1)

		// user.Current().Username normally produces something like 'USERDOMAIN\USERNAME'
		d := os.Getenv("USERDOMAIN")
		if len(d) != 0 {
			userName = d + "_" + u
		} else {
			userName = u
		}
	} else {
		current, err := user.Current()
		if err == nil {
			userName = current.Username
		}
	}
}

// shortHostname returns its argument, truncating at the first period.
// For instance, given "www.google.com" it returns "www".
func shortHostname(hostname string) string {
	if i := strings.Index(hostname, "."); i >= 0 {
		return hostname[:i]
	}
	return hostname
}

// logName returns a new log file name containing tag, with start time t, and
// the name for the symlink for tag.
func logName(tag string, t time.Time) (name, link string) {
	name = fmt.Sprintf("%s.%s.%s.log.%s.%04d%02d%02d-%02d%02d%02d.%d",
		program,
		host,
		userName,
		tag,
		t.Year(),
		t.Month(),
		t.Day(),
		t.Hour(),
		t.Minute(),
		t.Second(),
		pid)
	return name, program + "." + tag
}

var onceLogDirs sync.Once

// create creates a new log file and returns the file and its filename, which
// contains tag ("INFO", "FATAL", etc.) and t.  If the file is created
// successfully, create also attempts to update the symlink for that tag, ignoring
// errors.
// The startup argument indicates whether this is the initial startup of klog.
// If startup is true, existing files are opened for appending instead of truncated.
func create(tag string, t time.Time, startup bool) (f *os.File, filename string, err error) {
	if logging.logFile != "" {
		f, err := openOrCreate(logging.logFile, startup)
		if err == nil {
			return f, logging.logFile, nil
		}
		return nil, "", fmt.Errorf("log: unable to create log: %v", err)
	}
	onceLogDirs.Do(createLogDirs)
	if len(logDirs) == 0 {
		return nil, "", errors.New("log: no log dirs")
	}
	name, link := logName(tag, t)
	var lastErr error
	for _, dir := range logDirs {
		fname := filepath.Join(dir, name)
		f, err := openOrCreate(fname, startup)
		if err == nil {
			symlink := filepath.Join(dir, link)
			os.Remove(symlink)        // ignore err
			os.Symlink(name, symlink) // ignore err
			return f, fname, nil
		}
		lastErr = err
	}
	return nil, "", fmt.Errorf("log: cannot create log: %v", lastErr)
}

// The startup argument indicates whether this is the initial startup of klog.
// If startup is true, existing files are opened for appending instead of truncated.
func openOrCreate(name string, startup bool) (*os.File, error) {
	if startup {
		f, err := os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
		return f, err
	}
	f, err := os.Create(name)
	return f, err
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"io/ioutil"
	"net/http"
	"strconv"

	"github.com/clbanning/mxj"
	"github.com/mitchellh/mapstructure"

	"github.com/TykTechnologies/logrus"
	"github.com/TykTechnologies/tyk/apidef"
)

type ResponsetransformOptions struct {
	//FlushInterval time.Duration
}

type ResponseTransformMiddleware struct {
	Spec   *APISpec
	config ResponsetransformOptions
}

func (rt ResponseTransformMiddleware) New(c interface{}, spec *APISpec) (TykResponseHandler, error) {
	handler := ResponseTransformMiddleware{}
	moduleConfig := ResponsetransformOptions{}

	if err := mapstructure.Decode(c, &moduleConfig); err != nil {
		log.Error(err)
		return nil, err
	}

	handler.config = moduleConfig
	handler.Spec = spec

	log.Debug("Response body transform processor initialised")

	return handler, nil
}

func (rt ResponseTransformMiddleware) HandleResponse(rw http.ResponseWriter, res *http.Response, req *http.Request, ses *SessionState) error {
	_, versionPaths, _, _ := rt.Spec.GetVersionData(req)
	found, meta := rt.Spec.CheckSpecMatchesStatus(req.URL.Path, req.Method, versionPaths, TransformedResponse)
	if found {
		tmeta := meta.(*TransformSpec)

		// Read the body:
		defer res.Body.Close()
		body, err := ioutil.ReadAll(res.Body)
		if err != nil {
			return err
		}

		// Put into an interface:
		var bodyData interface{}
		switch tmeta.TemplateMeta.TemplateData.Input {
		case apidef.RequestXML:
			mxj.XmlCharsetReader = WrappedCharsetReader
			bodyData, err = mxj.NewMapXml(body) // unmarshal
			if err != nil {
				log.WithFields(logrus.Fields{
					"prefix":      "outbound-transform",
					"server_name": rt.Spec.APIDefinition.Proxy.TargetURL,
					"api_id":      rt.Spec.APIDefinition.APIID,
					"path":        req.URL.Path,
				}).Error("Error unmarshalling XML: ", err)
			}
		case apidef.RequestJSON:
			json.Unmarshal(body, &bodyData)
		default:
			json.Unmarshal(body, &bodyData)
		}

		// Apply to template
		var bodyBuffer bytes.Buffer
		if err = tmeta.Template.Execute(&bodyBuffer, bodyData); err != nil {
			log.WithFields(logrus.Fields{
				"prefix":      "outbound-transform",
				"server_name": rt.Spec.APIDefinition.Proxy.TargetURL,
				"api_id":      rt.Spec.APIDefinition.APIID,
				"path":        req.URL.Path,
			}).Error("Failed to apply template to request: ", err)
		}

		res.ContentLength = int64(bodyBuffer.Len())
		res.Header.Set("Content-Length", strconv.Itoa(bodyBuffer.Len()))
		res.Body = ioutil.NopCloser(&bodyBuffer)
	}

	return nil
}
<commit_msg>Unindent some code in a middleware<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"io/ioutil"
	"net/http"
	"strconv"

	"github.com/clbanning/mxj"
	"github.com/mitchellh/mapstructure"

	"github.com/TykTechnologies/logrus"
	"github.com/TykTechnologies/tyk/apidef"
)

type ResponsetransformOptions struct {
	//FlushInterval time.Duration
}

type ResponseTransformMiddleware struct {
	Spec   *APISpec
	config ResponsetransformOptions
}

func (rt ResponseTransformMiddleware) New(c interface{}, spec *APISpec) (TykResponseHandler, error) {
	handler := ResponseTransformMiddleware{}
	moduleConfig := ResponsetransformOptions{}

	if err := mapstructure.Decode(c, &moduleConfig); err != nil {
		log.Error(err)
		return nil, err
	}

	handler.config = moduleConfig
	handler.Spec = spec

	log.Debug("Response body transform processor initialised")

	return handler, nil
}

func (rt ResponseTransformMiddleware) HandleResponse(rw http.ResponseWriter, res *http.Response, req *http.Request, ses *SessionState) error {
	_, versionPaths, _, _ := rt.Spec.GetVersionData(req)
	found, meta := rt.Spec.CheckSpecMatchesStatus(req.URL.Path, req.Method, versionPaths, TransformedResponse)
	if !found {
		return nil
	}
	tmeta := meta.(*TransformSpec)

	// Read the body:
	defer res.Body.Close()
	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return err
	}

	// Put into an interface:
	var bodyData interface{}
	switch tmeta.TemplateMeta.TemplateData.Input {
	case apidef.RequestXML:
		mxj.XmlCharsetReader = WrappedCharsetReader
		bodyData, err = mxj.NewMapXml(body) // unmarshal
		if err != nil {
			log.WithFields(logrus.Fields{
				"prefix":      "outbound-transform",
				"server_name": rt.Spec.APIDefinition.Proxy.TargetURL,
				"api_id":      rt.Spec.APIDefinition.APIID,
				"path":        req.URL.Path,
			}).Error("Error unmarshalling XML: ", err)
		}
	case apidef.RequestJSON:
		json.Unmarshal(body, &bodyData)
	default:
		json.Unmarshal(body, &bodyData)
	}

	// Apply to template
	var bodyBuffer bytes.Buffer
	if err = tmeta.Template.Execute(&bodyBuffer, bodyData); err != nil {
		log.WithFields(logrus.Fields{
			"prefix":      "outbound-transform",
			"server_name": rt.Spec.APIDefinition.Proxy.TargetURL,
			"api_id":      rt.Spec.APIDefinition.APIID,
			"path":        req.URL.Path,
		}).Error("Failed to apply template to request: ", err)
	}

	res.ContentLength = int64(bodyBuffer.Len())
	res.Header.Set("Content-Length", strconv.Itoa(bodyBuffer.Len()))
	res.Body = ioutil.NopCloser(&bodyBuffer)

	return nil
}
<|endoftext|>