<commit_before>package untappd

import (
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
	"strings"
)

const (
	// untappdOAuthAuthenticate is a URL pattern which is interpolated with
	// an Untappd APIv4 client ID and redirect URL.  The resulting URL can
	// be returned to clients to begin the authentication process.
	untappdOAuthAuthenticate = "https://untappd.com/oauth/authenticate/?client_id=%s&response_type=code&redirect_url=%s"

	// untappdOAuthAuthorize is a URL pattern which is interpolated with
	// an Untappd APIv4 client ID, client secret, and redirect URL.
	// The resulting URL is requested by AuthHandler.ServeHTTP, generating
	// an Access Token for client consumption.
	untappdOAuthAuthorize = "https://untappd.com/oauth/authorize/?client_id=%s&client_secret=%s&response_type=code&redirect_url=%s"
)

// AuthService is a "service" which allows access to API methods which require
// authentication.
type AuthService struct {
	client *Client
}

// AuthHandler implements http.Handler, and provides a simple process for
// authenticating users using OAuth with Untappd APIv4.
type AuthHandler struct {
	clientID     string
	clientSecret string
	redirectURL  *url.URL
	oAuthURL     *url.URL
	handler      TokenHandlerFunc
	client       *http.Client
}

// TokenHandlerFunc is a function which is invoked at the end of a successful
// AuthHandler authentication process.  The token generated during the process is
// provided via the token parameter, and the HTTP request and response writers are
// available for further HTTP processing.
type TokenHandlerFunc func(token string, w http.ResponseWriter, r *http.Request)

// defaultTokenFn is the default implementation of TokenHandlerFunc, and is used
// automatically by NewAuthHandler, unless a custom TokenHandlerFunc is provided.
// This function simply prints the token to the HTTP response writer.
var defaultTokenFn = func(token string, w http.ResponseWriter, r *http.Request) {
	if _, err := w.Write([]byte(token)); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

// NewAuthHandler creates a http.Handler which can be used to easily authenticate
// a user using the Server Side Authentication process, documented here:
// https://untappd.com/api/docs#authentication.
//
// The first return parameter is the http.Handler described above.  The second is
// a URL which should be provided to a user, so that they can begin the
// authentication flow.  The third contains any errors which may have occurred
// during setup.
//
// The client ID, client secret, and redirectURL parameters are mandatory.
//
// The TokenHandlerFunc parameter can be used to provide a custom handler which
// contains an access token, and HTTP request and response writers, for further
// processing. The TokenHandlerFunc is only called upon successful authentication.
// Otherwise, an HTTP error is returned to the client.  If no TokenHandlerFunc is
// provided, a default one which writes the token to the HTTP response body will
// be used.
//
// The http.Client parameter can be used to provide a custom http.Client which
// obeys timeouts, etc.  This client is used to communicate with an upstream
// OAuth authentication server.  If no http.Client is provided, http.DefaultClient
// will be used.
func NewAuthHandler(clientID string, clientSecret string, redirectURL string, fn TokenHandlerFunc, client *http.Client) (*AuthHandler, *url.URL, error) {
	// Disallow empty ID and secret
	if clientID == "" {
		return nil, nil, ErrNoClientID
	}
	if clientSecret == "" {
		return nil, nil, ErrNoClientSecret
	}

	// Validate user redirect URL
	ru, err := url.Parse(redirectURL)
	if err != nil {
		return nil, nil, err
	}

	// Validate client authentication URL
	cu, err := url.Parse(fmt.Sprintf(
		untappdOAuthAuthenticate,
		clientID,
		ru.String(),
	))
	if err != nil {
		return nil, nil, err
	}

	// Validate OAuth URL
	ou, err := url.Parse(fmt.Sprintf(
		untappdOAuthAuthorize,
		clientID,
		clientSecret,
		ru.String(),
	))

	// If no token handler is set, use default
	if fn == nil {
		fn = defaultTokenFn
	}

	// If no client set, use http.DefaultClient
	if client == nil {
		client = http.DefaultClient
	}

	return &AuthHandler{
		clientID:     clientID,
		clientSecret: clientSecret,
		redirectURL:  ru,
		oAuthURL:     ou,
		handler:      fn,
		client:       client,
	}, cu, nil
}

// ServeHTTP implements http.Handler, and provides a simple http.Handler which
// can properly authenticate using the Server Side Authentication method outlined
// in Untappd documentation: https://untappd.com/api/docs#authentication.
func (a *AuthHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	// Verify correct HTTP method
	if r.Method != "GET" {
		http.Error(w, "only GET requests are allowed", http.StatusMethodNotAllowed)
		return
	}

	// Verify non-empty code parameter
	code := r.URL.Query().Get("code")
	if code == "" {
		http.Error(w, "no 'code' GET parameter", http.StatusBadRequest)
		return
	}

	// Perform HTTP GET request to retrieve token using the
	// code provided from query parameter
	res, err := a.client.Get(a.oAuthURL.String() + "&code=" + code)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	defer res.Body.Close()

	// Verify authentication server did not return an error
	if c := res.StatusCode; c > 299 || c < 200 {
		http.Error(w, fmt.Sprintf("authentication server error: HTTP %03d", c), http.StatusBadGateway)
		return
	}

	// Verify authentication server returned JSON
	if !strings.Contains(res.Header.Get("Content-Type"), jsonContentType) {
		http.Error(w, "authentication server sent non-JSON content", http.StatusBadGateway)
		return
	}

	// Temporary struct for JSON body
	var v struct {
		Response struct {
			AccessToken string `json:"access_token"`
		} `json:"response"`
	}

	// Decode JSON body to retrieve token
	if err := json.NewDecoder(res.Body).Decode(&v); err != nil {
		http.Error(w, err.Error(), http.StatusBadGateway)
		return
	}

	// Invoke TokenHandlerFunc to provide easy access to the generated token,
	// so the client can do whatever they please with it
	a.handler(v.Response.AccessToken, w, r)
}
<commit_msg>auth: check error in NewAuthHandler<commit_after>package untappd

import (
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
	"strings"
)

const (
	// untappdOAuthAuthenticate is a URL pattern which is interpolated with
	// an Untappd APIv4 client ID and redirect URL.  The resulting URL can
	// be returned to clients to begin the authentication process.
	untappdOAuthAuthenticate = "https://untappd.com/oauth/authenticate/?client_id=%s&response_type=code&redirect_url=%s"

	// untappdOAuthAuthorize is a URL pattern which is interpolated with
	// an Untappd APIv4 client ID, client secret, and redirect URL.
	// The resulting URL is requested by AuthHandler.ServeHTTP, generating
	// an Access Token for client consumption.
	untappdOAuthAuthorize = "https://untappd.com/oauth/authorize/?client_id=%s&client_secret=%s&response_type=code&redirect_url=%s"
)

// AuthService is a "service" which allows access to API methods which require
// authentication.
type AuthService struct {
	client *Client
}

// AuthHandler implements http.Handler, and provides a simple process for
// authenticating users using OAuth with Untappd APIv4.
type AuthHandler struct {
	clientID     string
	clientSecret string
	redirectURL  *url.URL
	oAuthURL     *url.URL
	handler      TokenHandlerFunc
	client       *http.Client
}

// TokenHandlerFunc is a function which is invoked at the end of a successful
// AuthHandler authentication process.  The token generated during the process is
// provided via the token parameter, and the HTTP request and response writers are
// available for further HTTP processing.
type TokenHandlerFunc func(token string, w http.ResponseWriter, r *http.Request)

// defaultTokenFn is the default implementation of TokenHandlerFunc, and is used
// automatically by NewAuthHandler, unless a custom TokenHandlerFunc is provided.
// This function simply prints the token to the HTTP response writer.
var defaultTokenFn = func(token string, w http.ResponseWriter, r *http.Request) {
	if _, err := w.Write([]byte(token)); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

// NewAuthHandler creates a http.Handler which can be used to easily authenticate
// a user using the Server Side Authentication process, documented here:
// https://untappd.com/api/docs#authentication.
//
// The first return parameter is the http.Handler described above.  The second is
// a URL which should be provided to a user, so that they can begin the
// authentication flow.  The third contains any errors which may have occurred
// during setup.
//
// The client ID, client secret, and redirectURL parameters are mandatory.
//
// The TokenHandlerFunc parameter can be used to provide a custom handler which
// contains an access token, and HTTP request and response writers, for further
// processing. The TokenHandlerFunc is only called upon successful authentication.
// Otherwise, an HTTP error is returned to the client.  If no TokenHandlerFunc is
// provided, a default one which writes the token to the HTTP response body will
// be used.
//
// The http.Client parameter can be used to provide a custom http.Client which
// obeys timeouts, etc.  This client is used to communicate with an upstream
// OAuth authentication server.  If no http.Client is provided, http.DefaultClient
// will be used.
func NewAuthHandler(clientID string, clientSecret string, redirectURL string, fn TokenHandlerFunc, client *http.Client) (*AuthHandler, *url.URL, error) {
	// Disallow empty ID and secret
	if clientID == "" {
		return nil, nil, ErrNoClientID
	}
	if clientSecret == "" {
		return nil, nil, ErrNoClientSecret
	}

	// Validate user redirect URL
	ru, err := url.Parse(redirectURL)
	if err != nil {
		return nil, nil, err
	}

	// Validate client authentication URL
	cu, err := url.Parse(fmt.Sprintf(
		untappdOAuthAuthenticate,
		clientID,
		ru.String(),
	))
	if err != nil {
		return nil, nil, err
	}

	// Validate OAuth URL
	ou, err := url.Parse(fmt.Sprintf(
		untappdOAuthAuthorize,
		clientID,
		clientSecret,
		ru.String(),
	))
	if err != nil {
		return nil, nil, err
	}

	// If no token handler is set, use default
	if fn == nil {
		fn = defaultTokenFn
	}

	// If no client set, use http.DefaultClient
	if client == nil {
		client = http.DefaultClient
	}

	return &AuthHandler{
		clientID:     clientID,
		clientSecret: clientSecret,
		redirectURL:  ru,
		oAuthURL:     ou,
		handler:      fn,
		client:       client,
	}, cu, nil
}

// ServeHTTP implements http.Handler, and provides a simple http.Handler which
// can properly authenticate using the Server Side Authentication method outlined
// in Untappd documentation: https://untappd.com/api/docs#authentication.
func (a *AuthHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	// Verify correct HTTP method
	if r.Method != "GET" {
		http.Error(w, "only GET requests are allowed", http.StatusMethodNotAllowed)
		return
	}

	// Verify non-empty code parameter
	code := r.URL.Query().Get("code")
	if code == "" {
		http.Error(w, "no 'code' GET parameter", http.StatusBadRequest)
		return
	}

	// Perform HTTP GET request to retrieve token using the
	// code provided from query parameter
	res, err := a.client.Get(a.oAuthURL.String() + "&code=" + code)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	defer res.Body.Close()

	// Verify authentication server did not return an error
	if c := res.StatusCode; c > 299 || c < 200 {
		http.Error(w, fmt.Sprintf("authentication server error: HTTP %03d", c), http.StatusBadGateway)
		return
	}

	// Verify authentication server returned JSON
	if !strings.Contains(res.Header.Get("Content-Type"), jsonContentType) {
		http.Error(w, "authentication server sent non-JSON content", http.StatusBadGateway)
		return
	}

	// Temporary struct for JSON body
	var v struct {
		Response struct {
			AccessToken string `json:"access_token"`
		} `json:"response"`
	}

	// Decode JSON body to retrieve token
	if err := json.NewDecoder(res.Body).Decode(&v); err != nil {
		http.Error(w, err.Error(), http.StatusBadGateway)
		return
	}

	// Invoke TokenHandlerFunc to provide easy access to the generated token,
	// so the client can do whatever they please with it
	a.handler(v.Response.AccessToken, w, r)
}
<|endoftext|>


<commit_before>package registry

import (
	"errors"
	"fmt"
	"os"
	"reflect"
	"strconv"
	"strings"
	"sync"
	"time"
)

var errInvalidValue = errors.New("Invalid value")

var (
	tags = []string{"default", "env", "flag", "registry"}
)

type config struct {
	rawConfig sync.Locker
	ident     string
	items     []item
}

func (r *registry) Bind(i sync.Locker) error {
	cfg := config{
		rawConfig: i,
		ident:     fmt.Sprintf("%s.%d", reflect.TypeOf(i).Elem().Name(), len(r.configs)+1),
	}
	err := cfg.bind(i, ``)
	if err != nil {
		return err
	}
	r.configs = append(r.configs, cfg)
	if r.refreshInterval != -1 {
		r.bindChan <- struct{}{}
	}
	return nil
}

func (cfg *config) callOnUpdatedMethod(updatedItemKeys []string) {
	for _, key := range updatedItemKeys {
		methodValue := reflect.ValueOf(cfg.rawConfig).MethodByName("OnUpdate" + key)
		if !methodValue.IsValid() {
			continue
		}
		methodValue.Call([]reflect.Value{})
	}
}

type item struct {
	key       string // registry key
	path      string // field path (SomeField.AnotherField.LeafField -> "SomeFieldAnotherFieldLeafField")
	reference reflect.Value
}

var typeOfDuration = reflect.TypeOf(time.Duration(0))

func (i *item) equal(value interface{}) bool {
	return reflect.DeepEqual(i.reference.Interface(), value)
}

func (i *item) set(rawValue string) error {
	if len(rawValue) == 0 {
		return nil
	}

	var (
		err          error
		defaultValue interface{}
	)

	switch i.reference.Type() {
	case typeOfDuration:
		defaultValue, err = time.ParseDuration(rawValue)
	default:
		defaultValue, err = defaultByKind(i.reference.Type(), rawValue)
	}

	if err != nil {
		return err
	}

	if i.reference.CanSet() && defaultValue != nil {
		i.reference.Set(reflect.ValueOf(defaultValue))
	}
	return nil
}

func defaultByKind(tp reflect.Type, rawValue string) (defaultValue interface{}, err error) {
	switch tp.Kind() {
	case reflect.String:
		defaultValue = rawValue
	case reflect.Int:
		if defaultValue, err = strconv.ParseInt(rawValue, 10, 0); err == nil {
			defaultValue = int(defaultValue.(int64))
		}
	case reflect.Int8:
		if defaultValue, err = strconv.ParseInt(rawValue, 10, 8); err == nil {
			defaultValue = int8(defaultValue.(int64))
		}
	case reflect.Int16:
		if defaultValue, err = strconv.ParseInt(rawValue, 10, 16); err == nil {
			defaultValue = int16(defaultValue.(int64))
		}
	case reflect.Int32:
		if defaultValue, err = strconv.ParseInt(rawValue, 10, 32); err == nil {
			defaultValue = int32(defaultValue.(int64))
		}
	case reflect.Int64:
		defaultValue, err = strconv.ParseInt(rawValue, 10, 64)
	case reflect.Uint:
		if defaultValue, err = strconv.ParseUint(rawValue, 10, 0); err == nil {
			defaultValue = uint(defaultValue.(uint64))
		}
	case reflect.Uint8:
		if defaultValue, err = strconv.ParseUint(rawValue, 10, 8); err == nil {
			defaultValue = uint8(defaultValue.(uint64))
		}
	case reflect.Uint16:
		if defaultValue, err = strconv.ParseUint(rawValue, 10, 16); err == nil {
			defaultValue = uint16(defaultValue.(uint64))
		}
	case reflect.Uint32:
		if defaultValue, err = strconv.ParseUint(rawValue, 10, 32); err == nil {
			defaultValue = uint32(defaultValue.(uint64))
		}
	case reflect.Uint64:
		defaultValue, err = strconv.ParseUint(rawValue, 10, 64)
	case reflect.Float32:
		if defaultValue, err = strconv.ParseFloat(rawValue, 10); err == nil {
			defaultValue = float32(defaultValue.(float64))
		}
	case reflect.Float64:
		defaultValue, err = strconv.ParseFloat(rawValue, 10)
	case reflect.Bool:
		defaultValue, err = strconv.ParseBool(rawValue)
	case reflect.Slice:
		values := strings.Split(rawValue, ",")
		rslice := reflect.MakeSlice(tp, len(values), cap(values))
		if len(values) > 0 {
			fieldType := rslice.Index(0).Type()
			for i, v := range values {
				r, err := defaultByKind(fieldType, v)
				if err != nil {
					break
				}
				rval := reflect.ValueOf(r)
				if !rval.IsValid() {
					continue
				}
				rslice.Index(i).Set(rval)
			}
		}
		defaultValue = rslice.Interface()
	}
	return
}

func (cfg *config) bind(i interface{}, prefix string) error {
	var (
		rt = reflect.TypeOf(i)
		rv = reflect.ValueOf(i)
	)

	if rt.Kind() == reflect.Ptr {
		rt = rt.Elem()
		rv = rv.Elem()
	}

	var fields []string

	for i := 0; i < rt.NumField(); i++ {
		var (
			field     = rt.Field(i)
			value     = rv.FieldByName(field.Name)
			fieldPath = prefix + field.Name
		)
		if len(field.PkgPath) != 0 { // enexported
			continue
		}
		switch field.Type.Kind() {
		case reflect.Struct:
			err := cfg.bind(value.Addr().Interface(), fieldPath)
			if err != nil {
				return fmt.Errorf("'%s': %v", field.Name, err)
			}
		default:
			item, err := makeItem(field, fieldPath, value)
			if err != nil {
				return fmt.Errorf("'%s': %v", field.Name, err)
			}
			if len(item.key) != 0 {
				cfg.items = append(cfg.items, item)
			}
			fields = append(fields, fieldPath)
		}
	}

	cfg.callOnUpdatedMethod(fields) // Call method "OnUpdate<variableName>" if exists
	return nil
}

func makeItem(field reflect.StructField, path string, value reflect.Value) (item, error) {
	if value.Kind() == reflect.Ptr {
		value = value.Elem()
	}

	if !value.IsValid() {
		return item{}, errInvalidValue
	}

	var (
		tagValue    string
		rawValue    string
		registryKey string
	)

	for _, key := range tags {
		tagValue = field.Tag.Get(key)
		switch key {
		case "registry":
			registryKey = tagValue
		case "default":
			rawValue = tagValue
		case "env":
			if value := os.Getenv(tagValue); len(value) != 0 {
				rawValue = value
			}
		case "flag":
			if len(tagValue) != 0 {
				if value := flag(tagValue); len(value) != 0 {
					rawValue = value
				}
			}
		}
	}

	new := item{key: registryKey, reference: value, path: path}

	if err := new.set(rawValue); err != nil {
		return item{}, err
	}

	return new, nil
}

func flag(name string) string {
	prefix := "--"
	if len(name) == 1 {
		prefix = "-"
	}
	name = prefix + name
	for i, arg := range args {
		if strings.Contains(arg, "=") && strings.HasPrefix(arg, name) {
			if parts := strings.Split(arg, "="); len(parts) == 2 {
				return parts[1]
			}
		}
		if arg == name {
			if len(args) >= i {
				return args[i+1]
			}
		}
	}
	return ""
}
<commit_msg>break on on invalid value<commit_after>package registry

import (
	"errors"
	"fmt"
	"os"
	"reflect"
	"strconv"
	"strings"
	"sync"
	"time"
)

var errInvalidValue = errors.New("Invalid value")

var (
	tags = []string{"default", "env", "flag", "registry"}
)

type config struct {
	rawConfig sync.Locker
	ident     string
	items     []item
}

func (r *registry) Bind(i sync.Locker) error {
	cfg := config{
		rawConfig: i,
		ident:     fmt.Sprintf("%s.%d", reflect.TypeOf(i).Elem().Name(), len(r.configs)+1),
	}
	err := cfg.bind(i, ``)
	if err != nil {
		return err
	}
	r.configs = append(r.configs, cfg)
	if r.refreshInterval != -1 {
		r.bindChan <- struct{}{}
	}
	return nil
}

func (cfg *config) callOnUpdatedMethod(updatedItemKeys []string) {
	for _, key := range updatedItemKeys {
		methodValue := reflect.ValueOf(cfg.rawConfig).MethodByName("OnUpdate" + key)
		if !methodValue.IsValid() {
			continue
		}
		methodValue.Call([]reflect.Value{})
	}
}

type item struct {
	key       string // registry key
	path      string // field path (SomeField.AnotherField.LeafField -> "SomeFieldAnotherFieldLeafField")
	reference reflect.Value
}

var typeOfDuration = reflect.TypeOf(time.Duration(0))

func (i *item) equal(value interface{}) bool {
	return reflect.DeepEqual(i.reference.Interface(), value)
}

func (i *item) set(rawValue string) error {
	if len(rawValue) == 0 {
		return nil
	}

	var (
		err          error
		defaultValue interface{}
	)

	switch i.reference.Type() {
	case typeOfDuration:
		defaultValue, err = time.ParseDuration(rawValue)
	default:
		defaultValue, err = defaultByKind(i.reference.Type(), rawValue)
	}

	if err != nil {
		return err
	}

	if i.reference.CanSet() && defaultValue != nil {
		i.reference.Set(reflect.ValueOf(defaultValue))
	}
	return nil
}

func defaultByKind(tp reflect.Type, rawValue string) (defaultValue interface{}, err error) {
	switch tp.Kind() {
	case reflect.String:
		defaultValue = rawValue
	case reflect.Int:
		if defaultValue, err = strconv.ParseInt(rawValue, 10, 0); err == nil {
			defaultValue = int(defaultValue.(int64))
		}
	case reflect.Int8:
		if defaultValue, err = strconv.ParseInt(rawValue, 10, 8); err == nil {
			defaultValue = int8(defaultValue.(int64))
		}
	case reflect.Int16:
		if defaultValue, err = strconv.ParseInt(rawValue, 10, 16); err == nil {
			defaultValue = int16(defaultValue.(int64))
		}
	case reflect.Int32:
		if defaultValue, err = strconv.ParseInt(rawValue, 10, 32); err == nil {
			defaultValue = int32(defaultValue.(int64))
		}
	case reflect.Int64:
		defaultValue, err = strconv.ParseInt(rawValue, 10, 64)
	case reflect.Uint:
		if defaultValue, err = strconv.ParseUint(rawValue, 10, 0); err == nil {
			defaultValue = uint(defaultValue.(uint64))
		}
	case reflect.Uint8:
		if defaultValue, err = strconv.ParseUint(rawValue, 10, 8); err == nil {
			defaultValue = uint8(defaultValue.(uint64))
		}
	case reflect.Uint16:
		if defaultValue, err = strconv.ParseUint(rawValue, 10, 16); err == nil {
			defaultValue = uint16(defaultValue.(uint64))
		}
	case reflect.Uint32:
		if defaultValue, err = strconv.ParseUint(rawValue, 10, 32); err == nil {
			defaultValue = uint32(defaultValue.(uint64))
		}
	case reflect.Uint64:
		defaultValue, err = strconv.ParseUint(rawValue, 10, 64)
	case reflect.Float32:
		if defaultValue, err = strconv.ParseFloat(rawValue, 10); err == nil {
			defaultValue = float32(defaultValue.(float64))
		}
	case reflect.Float64:
		defaultValue, err = strconv.ParseFloat(rawValue, 10)
	case reflect.Bool:
		defaultValue, err = strconv.ParseBool(rawValue)
	case reflect.Slice:
		values := strings.Split(rawValue, ",")
		rslice := reflect.MakeSlice(tp, len(values), cap(values))
		if len(values) > 0 {
			fieldType := rslice.Index(0).Type()
			for i, v := range values {
				r, err := defaultByKind(fieldType, v)
				if err != nil {
					break
				}
				rval := reflect.ValueOf(r)
				if !rval.IsValid() {
					break
				}
				rslice.Index(i).Set(rval)
			}
		}
		defaultValue = rslice.Interface()
	}
	return
}

func (cfg *config) bind(i interface{}, prefix string) error {
	var (
		rt = reflect.TypeOf(i)
		rv = reflect.ValueOf(i)
	)

	if rt.Kind() == reflect.Ptr {
		rt = rt.Elem()
		rv = rv.Elem()
	}

	var fields []string

	for i := 0; i < rt.NumField(); i++ {
		var (
			field     = rt.Field(i)
			value     = rv.FieldByName(field.Name)
			fieldPath = prefix + field.Name
		)
		if len(field.PkgPath) != 0 { // enexported
			continue
		}
		switch field.Type.Kind() {
		case reflect.Struct:
			err := cfg.bind(value.Addr().Interface(), fieldPath)
			if err != nil {
				return fmt.Errorf("'%s': %v", field.Name, err)
			}
		default:
			item, err := makeItem(field, fieldPath, value)
			if err != nil {
				return fmt.Errorf("'%s': %v", field.Name, err)
			}
			if len(item.key) != 0 {
				cfg.items = append(cfg.items, item)
			}
			fields = append(fields, fieldPath)
		}
	}

	cfg.callOnUpdatedMethod(fields) // Call method "OnUpdate<variableName>" if exists
	return nil
}

func makeItem(field reflect.StructField, path string, value reflect.Value) (item, error) {
	if value.Kind() == reflect.Ptr {
		value = value.Elem()
	}

	if !value.IsValid() {
		return item{}, errInvalidValue
	}

	var (
		tagValue    string
		rawValue    string
		registryKey string
	)

	for _, key := range tags {
		tagValue = field.Tag.Get(key)
		switch key {
		case "registry":
			registryKey = tagValue
		case "default":
			rawValue = tagValue
		case "env":
			if value := os.Getenv(tagValue); len(value) != 0 {
				rawValue = value
			}
		case "flag":
			if len(tagValue) != 0 {
				if value := flag(tagValue); len(value) != 0 {
					rawValue = value
				}
			}
		}
	}

	new := item{key: registryKey, reference: value, path: path}

	if err := new.set(rawValue); err != nil {
		return item{}, err
	}

	return new, nil
}

func flag(name string) string {
	prefix := "--"
	if len(name) == 1 {
		prefix = "-"
	}
	name = prefix + name
	for i, arg := range args {
		if strings.Contains(arg, "=") && strings.HasPrefix(arg, name) {
			if parts := strings.Split(arg, "="); len(parts) == 2 {
				return parts[1]
			}
		}
		if arg == name {
			if len(args) >= i {
				return args[i+1]
			}
		}
	}
	return ""
}
<|endoftext|>


<commit_before>// Copyright ©2012 Dan Kortschak <dan.kortschak@adelaide.edu.au>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

// Package boom is a wrapper for the samtools bam library.
package boom

// http://samtools.sourceforge.net/samtools/sam/index.html

/*
#cgo CFLAGS: -g -O2 -fPIC -m64 -pthread
#cgo LDFLAGS: -lz
#include "sam.h"
*/
import "C"

import (
	"fmt"
	"io"
	"reflect"
	"runtime"
	"unsafe"
)

var (
	valueIsNil       = fmt.Errorf("boom: value is nil")
	notBamFile       = fmt.Errorf("boom: not bam file")
	couldNotAllocate = fmt.Errorf("boom: could not allocate")
	cannotAddr       = fmt.Errorf("boom: cannot address value")
)

type bamRecord struct {
	b *C.bam1_t
}

func newBamRecord(b *C.bam1_t) (br *bamRecord) {
	br = &bamRecord{b}
	runtime.SetFinalizer(br, (*bamRecord).bamRecordFree)

	return
}

func (br *bamRecord) tid() int32 {
	if br.b != nil {
		return int32(br.b.core.tid)
	}
	panic(valueIsNil)
}
func (br *bamRecord) pos() int32 {
	if br.b != nil {
		return int32(br.b.core.pos)
	}
	panic(valueIsNil)
}
func (br *bamRecord) bin() uint {
	if br.b != nil {
		return uint(br.b.core.bin)
	}
	panic(valueIsNil)
}
func (br *bamRecord) qual() byte {
	if br.b != nil {
		return byte(br.b.core.qual)
	}
	panic(valueIsNil)
}
func (br *bamRecord) lQname() byte {
	if br.b != nil {
		return byte(br.b.core.l_qname)
	}
	panic(valueIsNil)
}
func (br *bamRecord) flag() uint {
	if br.b != nil {
		return uint(br.b.core.flag)
	}
	panic(valueIsNil)
}
func (br *bamRecord) nCigar() uint {
	if br.b != nil {
		return uint(br.b.core.n_cigar)
	}
	panic(valueIsNil)
}
func (br *bamRecord) lQseq() int32 {
	if br.b != nil {
		return int32(br.b.core.l_qseq)
	}
	panic(valueIsNil)
}
func (br *bamRecord) mtid() int32 {
	if br.b != nil {
		return int32(br.b.core.mtid)
	}
	panic(valueIsNil)
}
func (br *bamRecord) mpos() int32 {
	if br.b != nil {
		return int32(br.b.core.mpos)
	}
	panic(valueIsNil)
}
func (br *bamRecord) isize() int32 {
	if br.b != nil {
		return int32(br.b.core.isize)
	}
	panic(valueIsNil)
}
func (br *bamRecord) lAux() int {
	if br.b != nil {
		return int(br.b.l_aux)
	}
	panic(valueIsNil)
}
func (br *bamRecord) dataLen() int {
	if br.b != nil {
		return int(br.b.data_len)
	}
	panic(valueIsNil)
}
func (br *bamRecord) dataCap() int {
	if br.b != nil {
		return int(br.b.m_data)
	}
	panic(valueIsNil)
}
func (br *bamRecord) data() uintptr {
	if br.b != nil {
		return uintptr(unsafe.Pointer(br.b.data))
	}
	panic(valueIsNil)
}
func (br *bamRecord) bamRecordFree() {
	if br.b != nil {
		C.free(unsafe.Pointer(br.b))
		br.b = nil
	}
}

type samFile struct {
	fp *C.samfile_t
}

func (sf *samFile) fileType() int {
	if sf.fp != nil {
		return int(sf.fp._type)
	}
	panic(valueIsNil)
}

func samOpen(filename, mode string, aux header) (sf *samFile, err error) {
	fn, m := C.CString(filename), C.CString(mode)
	defer C.free(unsafe.Pointer(fn))
	defer C.free(unsafe.Pointer(m))

	var auxAddr uintptr
	switch aux.(type) {
	case textHeader:
		xv := reflect.ValueOf(aux)
		if xv.Len() > 0 {
			auxAddr = xv.Index(0).UnsafeAddr()
		} else {
			auxAddr = 0
		}
	case *bamHeader:
		auxAddr = reflect.ValueOf(aux).UnsafeAddr()
	default:
		panic(fmt.Sprintf("boom: wrong type %T", aux))
	}

	fp, err := C.samopen(
		(*C.char)(unsafe.Pointer(fn)),
		(*C.char)(unsafe.Pointer(m)),
		unsafe.Pointer(auxAddr),
	)
	sf = &samFile{fp: (*C.samfile_t)(unsafe.Pointer(fp))}
	runtime.SetFinalizer(sf, (*samFile).samClose)

	return
}

func (sf *samFile) samClose() error {
	if sf.fp == nil {
		return valueIsNil
	}

	C.samclose((*C.samfile_t)(unsafe.Pointer(sf.fp)))

	return nil
}

func (sf *samFile) samRead() (n int, br *bamRecord, err error) {
	if sf.fp == nil {
		return 0, nil, valueIsNil
	}

	b := (*C.bam1_t)(unsafe.Pointer(C.malloc((C.size_t)(unsafe.Sizeof(C.bam1_t{})))))

	if b == nil {
		return 0, nil, couldNotAllocate
	}
	*b = C.bam1_t{}
	br = &bamRecord{
		b: b,
	}

	cn, err := C.samread(
		(*C.samfile_t)(unsafe.Pointer(sf.fp)),
		(*C.bam1_t)(unsafe.Pointer(br.b)),
	)
	n = int(cn)
	if n < 0 {
		err = io.EOF
	}

	return
}

func (sf *samFile) samWrite(br *bamRecord) (n int, err error) {
	if sf.fp == nil || br.b == nil {
		return 0, valueIsNil
	}

	return int(C.samwrite(
		(*C.samfile_t)(unsafe.Pointer(sf.fp)),
		(*C.bam1_t)(unsafe.Pointer(br.b)),
	)), nil
}

type bamIndex struct {
	idx *C.bam_index_t
}

func bamIndexBuild(filename string) (ret int, err error) {
	fn := C.CString(filename)
	defer C.free(unsafe.Pointer(fn))

	r, err := C.bam_index_build(
		(*C.char)(unsafe.Pointer(fn)),
	)

	return int(r), err
}

func bamIndexLoad(filename string) (bi *bamIndex, err error) {
	fn := C.CString(filename)
	defer C.free(unsafe.Pointer(fn))

	ip, err := C.bam_index_load(
		(*C.char)(unsafe.Pointer(fn)),
	)
	bi = &bamIndex{idx: (*C.bam_index_t)(unsafe.Pointer(ip))}
	runtime.SetFinalizer(bi, (*bamIndex).bamIndexDestroy)

	return
}

func (bi *bamIndex) bamIndexDestroy() (err error) {
	if bi.idx == nil {
		return valueIsNil
	}

	C.bam_index_destroy(
		(*C.bam_index_t)(unsafe.Pointer(bi.idx)),
	)

	return
}

type BamFetchFn func(*bamRecord, interface{}) int

func (sf *samFile) bamFetch(bi *bamIndex, tid, beg, end int, data interface{}, fn BamFetchFn) (ret int, err error) {
	if sf.fp == nil || bi.idx == nil {
		return 0, valueIsNil
	}

	if sf.fileType()&1 != 1 {
		return 0, notBamFile
	}

	dv := reflect.ValueOf(data)
	if dv.CanAddr() {
		return 0, cannotAddr
	}

	f := func(b *C.bam1_t, _ *[0]byte) C.int {
		return C.int(fn(&bamRecord{(*C.bam1_t)(unsafe.Pointer(b))}, data))
	}

	r := C.bam_fetch(
		(*C.BGZF)(unsafe.Pointer(sf.fp)),
		bi.idx,
		C.int(tid),
		C.int(beg),
		C.int(end),
		unsafe.Pointer(dv.UnsafeAddr()),
		(*[0]byte)(unsafe.Pointer(&f)),
	)

	return int(r), nil
}

type header interface {
	header()
}

type bamHeader struct {
	bh *C.bam_header_t
}

func (bh *bamHeader) header() {}

type textHeader []byte

func (th textHeader) header() {}
<commit_msg>Memory leak<commit_after>// Copyright ©2012 Dan Kortschak <dan.kortschak@adelaide.edu.au>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

// Package boom is a wrapper for the samtools bam library.
package boom

// http://samtools.sourceforge.net/samtools/sam/index.html

/*
#cgo CFLAGS: -g -O2 -fPIC -m64 -pthread
#cgo LDFLAGS: -lz
#include "sam.h"
*/
import "C"

import (
	"fmt"
	"io"
	"reflect"
	"runtime"
	"unsafe"
)

var (
	valueIsNil       = fmt.Errorf("boom: value is nil")
	notBamFile       = fmt.Errorf("boom: not bam file")
	couldNotAllocate = fmt.Errorf("boom: could not allocate")
	cannotAddr       = fmt.Errorf("boom: cannot address value")
)

type bamRecord struct {
	b *C.bam1_t
}

func newBamRecord(b *C.bam1_t) (br *bamRecord) {
	br = &bamRecord{b}
	runtime.SetFinalizer(br, (*bamRecord).bamRecordFree)

	return
}

func (br *bamRecord) tid() int32 {
	if br.b != nil {
		return int32(br.b.core.tid)
	}
	panic(valueIsNil)
}
func (br *bamRecord) pos() int32 {
	if br.b != nil {
		return int32(br.b.core.pos)
	}
	panic(valueIsNil)
}
func (br *bamRecord) bin() uint {
	if br.b != nil {
		return uint(br.b.core.bin)
	}
	panic(valueIsNil)
}
func (br *bamRecord) qual() byte {
	if br.b != nil {
		return byte(br.b.core.qual)
	}
	panic(valueIsNil)
}
func (br *bamRecord) lQname() byte {
	if br.b != nil {
		return byte(br.b.core.l_qname)
	}
	panic(valueIsNil)
}
func (br *bamRecord) flag() uint {
	if br.b != nil {
		return uint(br.b.core.flag)
	}
	panic(valueIsNil)
}
func (br *bamRecord) nCigar() uint {
	if br.b != nil {
		return uint(br.b.core.n_cigar)
	}
	panic(valueIsNil)
}
func (br *bamRecord) lQseq() int32 {
	if br.b != nil {
		return int32(br.b.core.l_qseq)
	}
	panic(valueIsNil)
}
func (br *bamRecord) mtid() int32 {
	if br.b != nil {
		return int32(br.b.core.mtid)
	}
	panic(valueIsNil)
}
func (br *bamRecord) mpos() int32 {
	if br.b != nil {
		return int32(br.b.core.mpos)
	}
	panic(valueIsNil)
}
func (br *bamRecord) isize() int32 {
	if br.b != nil {
		return int32(br.b.core.isize)
	}
	panic(valueIsNil)
}
func (br *bamRecord) lAux() int {
	if br.b != nil {
		return int(br.b.l_aux)
	}
	panic(valueIsNil)
}
func (br *bamRecord) dataLen() int {
	if br.b != nil {
		return int(br.b.data_len)
	}
	panic(valueIsNil)
}
func (br *bamRecord) dataCap() int {
	if br.b != nil {
		return int(br.b.m_data)
	}
	panic(valueIsNil)
}
func (br *bamRecord) data() uintptr {
	if br.b != nil {
		return uintptr(unsafe.Pointer(br.b.data))
	}
	panic(valueIsNil)
}
func (br *bamRecord) bamRecordFree() {
	if br.b != nil {
		C.free(unsafe.Pointer(br.b))
		br.b = nil
	}
}

type samFile struct {
	fp *C.samfile_t
}

func (sf *samFile) fileType() int {
	if sf.fp != nil {
		return int(sf.fp._type)
	}
	panic(valueIsNil)
}

func samOpen(filename, mode string, aux header) (sf *samFile, err error) {
	fn, m := C.CString(filename), C.CString(mode)
	defer C.free(unsafe.Pointer(fn))
	defer C.free(unsafe.Pointer(m))

	var auxAddr uintptr
	switch aux.(type) {
	case textHeader:
		xv := reflect.ValueOf(aux)
		if xv.Len() > 0 {
			auxAddr = xv.Index(0).UnsafeAddr()
		} else {
			auxAddr = 0
		}
	case *bamHeader:
		auxAddr = reflect.ValueOf(aux).UnsafeAddr()
	default:
		panic(fmt.Sprintf("boom: wrong type %T", aux))
	}

	fp, err := C.samopen(
		(*C.char)(unsafe.Pointer(fn)),
		(*C.char)(unsafe.Pointer(m)),
		unsafe.Pointer(auxAddr),
	)
	sf = &samFile{fp: (*C.samfile_t)(unsafe.Pointer(fp))}
	runtime.SetFinalizer(sf, (*samFile).samClose)

	return
}

func (sf *samFile) samClose() error {
	if sf.fp == nil {
		return valueIsNil
	}

	C.samclose((*C.samfile_t)(unsafe.Pointer(sf.fp)))

	return nil
}

func (sf *samFile) samRead() (n int, br *bamRecord, err error) {
	if sf.fp == nil {
		return 0, nil, valueIsNil
	}

	b := (*C.bam1_t)(unsafe.Pointer(C.malloc((C.size_t)(unsafe.Sizeof(C.bam1_t{})))))

	if b == nil {
		return 0, nil, couldNotAllocate
	}
	*b = C.bam1_t{}
	br = newBamRecord(b)

	cn, err := C.samread(
		(*C.samfile_t)(unsafe.Pointer(sf.fp)),
		(*C.bam1_t)(unsafe.Pointer(br.b)),
	)
	n = int(cn)
	if n < 0 {
		err = io.EOF
	}

	return
}

func (sf *samFile) samWrite(br *bamRecord) (n int, err error) {
	if sf.fp == nil || br.b == nil {
		return 0, valueIsNil
	}

	return int(C.samwrite(
		(*C.samfile_t)(unsafe.Pointer(sf.fp)),
		(*C.bam1_t)(unsafe.Pointer(br.b)),
	)), nil
}

type bamIndex struct {
	idx *C.bam_index_t
}

func bamIndexBuild(filename string) (ret int, err error) {
	fn := C.CString(filename)
	defer C.free(unsafe.Pointer(fn))

	r, err := C.bam_index_build(
		(*C.char)(unsafe.Pointer(fn)),
	)

	return int(r), err
}

func bamIndexLoad(filename string) (bi *bamIndex, err error) {
	fn := C.CString(filename)
	defer C.free(unsafe.Pointer(fn))

	ip, err := C.bam_index_load(
		(*C.char)(unsafe.Pointer(fn)),
	)
	bi = &bamIndex{idx: (*C.bam_index_t)(unsafe.Pointer(ip))}
	runtime.SetFinalizer(bi, (*bamIndex).bamIndexDestroy)

	return
}

func (bi *bamIndex) bamIndexDestroy() (err error) {
	if bi.idx == nil {
		return valueIsNil
	}

	C.bam_index_destroy(
		(*C.bam_index_t)(unsafe.Pointer(bi.idx)),
	)

	return
}

type BamFetchFn func(*bamRecord, interface{}) int

func (sf *samFile) bamFetch(bi *bamIndex, tid, beg, end int, data interface{}, fn BamFetchFn) (ret int, err error) {
	if sf.fp == nil || bi.idx == nil {
		return 0, valueIsNil
	}

	if sf.fileType()&1 != 1 {
		return 0, notBamFile
	}

	dv := reflect.ValueOf(data)
	if dv.CanAddr() {
		return 0, cannotAddr
	}

	f := func(b *C.bam1_t, _ *[0]byte) C.int {
		return C.int(fn(&bamRecord{(*C.bam1_t)(unsafe.Pointer(b))}, data))
	}

	r := C.bam_fetch(
		(*C.BGZF)(unsafe.Pointer(sf.fp)),
		bi.idx,
		C.int(tid),
		C.int(beg),
		C.int(end),
		unsafe.Pointer(dv.UnsafeAddr()),
		(*[0]byte)(unsafe.Pointer(&f)),
	)

	return int(r), nil
}

type header interface {
	header()
}

type bamHeader struct {
	bh *C.bam_header_t
}

func (bh *bamHeader) header() {}

type textHeader []byte

func (th textHeader) header() {}
<|endoftext|>


<commit_before>package micro

import (
	"encoding/binary"
	"fmt"
	"io"
	"log"
	"net"
	"sync/atomic"
)

var (
	nconnid uint64
)

type conn struct {
	state  int32 // 0: alive, 1: down
	id     uint64
	c      net.Conn
	chrq   chan *Packet
	chwq   chan *Packet
	chdown chan struct{}
	err    error
}

func (c *conn) shutdown(err error) {
	if !atomic.CompareAndSwapInt32(&c.state, 0, 1) {
		return
	}
	c.err = err
	c.c.Close()
	close(c.chdown)
}

func (c *conn) readloop() {
	for {
		pack, err := c.read()
		if err != nil {
			c.shutdown(err)
			return
		}
		if isDebug {
			log.Printf("session(%d) read %+v", c.id, pack)
		}
		if pack == nil {
			continue
		}
		select {
		case c.chrq <- pack:
		case <-c.chdown:
			return
		}
	}
}

func (c *conn) writeloop() {
	for {
		select {
		case pack := <-c.chwq:
			err := c.write(pack)
			if err != nil {
				c.shutdown(err)
				return
			}
			if isDebug {
				log.Printf("session(%d) write %+v", c.id, pack)
			}
		case <-c.chdown:
			return
		}
	}
}

func (c *conn) read() (*Packet, error) {
	var nbuf [4]byte
	_, err := io.ReadFull(c.c, nbuf[:])
	if err != nil {
		return nil, err
	}
	n := binary.LittleEndian.Uint32(nbuf[:])
	if n >= maxPacketSize {
		return nil, fmt.Errorf("invalid packet size: %d", n)
	}
	if isDebug {
		log.Printf("session(%d) read n(%d)", c.id, n)
	}
	buf := make([]byte, n)
	_, err = io.ReadFull(c.c, buf)
	if err != nil {
		return nil, err
	}
	pack := &Packet{}
	r := DecodePacket(pack, buf)
	if r != len(buf) {
		return nil, fmt.Errorf("invalid packet: %d", r)
	}
	return pack, nil
}

func (c *conn) write(pack *Packet) error {
	_, err := c.c.Write(EncodePacket(nil, pack))
	return err
}

func (c *conn) send(pack *Packet) bool {
	if atomic.LoadInt32(&c.state) == 0 {
		select {
		case c.chwq <- pack:
			return true
		case <-c.chdown:
		}
	}
	return false
}

func goconn(nc net.Conn) *conn {
	c := &conn{
		id:     atomic.AddUint64(&nconnid, 1),
		c:      nc,
		chrq:   make(chan *Packet, connReadCap),
		chwq:   make(chan *Packet, connWriteCap),
		chdown: make(chan struct{}),
	}
	go c.readloop()
	go c.writeloop()
	return c
}
<commit_msg>fix 0 size packet<commit_after>package micro

import (
	"encoding/binary"
	"fmt"
	"io"
	"log"
	"net"
	"sync/atomic"
)

var (
	nconnid uint64
)

type conn struct {
	state  int32 // 0: alive, 1: down
	id     uint64
	c      net.Conn
	chrq   chan *Packet
	chwq   chan *Packet
	chdown chan struct{}
	err    error
}

func (c *conn) shutdown(err error) {
	if !atomic.CompareAndSwapInt32(&c.state, 0, 1) {
		return
	}
	c.err = err
	c.c.Close()
	close(c.chdown)
}

func (c *conn) readloop() {
	for {
		pack, err := c.read()
		if err != nil {
			c.shutdown(err)
			return
		}
		if isDebug {
			log.Printf("session(%d) read %+v", c.id, pack)
		}
		if pack == nil {
			continue
		}
		select {
		case c.chrq <- pack:
		case <-c.chdown:
			return
		}
	}
}

func (c *conn) writeloop() {
	for {
		select {
		case pack := <-c.chwq:
			err := c.write(pack)
			if err != nil {
				c.shutdown(err)
				return
			}
			if isDebug {
				log.Printf("session(%d) write %+v", c.id, pack)
			}
		case <-c.chdown:
			return
		}
	}
}

func (c *conn) read() (*Packet, error) {
	var nbuf [4]byte
	_, err := io.ReadFull(c.c, nbuf[:])
	if err != nil {
		return nil, err
	}
	n := binary.LittleEndian.Uint32(nbuf[:])
	if n >= maxPacketSize {
		return nil, fmt.Errorf("invalid packet size: %d", n)
	}
	if isDebug {
		log.Printf("session(%d) read n(%d)", c.id, n)
	}
	buf := make([]byte, n)
	_, err = io.ReadFull(c.c, buf)
	if err != nil {
		return nil, err
	}
	pack := &Packet{}
	r := DecodePacket(pack, buf)
	if r == 0 || r != len(buf) {
		return nil, fmt.Errorf("invalid packet: %d", r)
	}
	return pack, nil
}

func (c *conn) write(pack *Packet) error {
	_, err := c.c.Write(EncodePacket(nil, pack))
	return err
}

func (c *conn) send(pack *Packet) bool {
	if atomic.LoadInt32(&c.state) == 0 {
		select {
		case c.chwq <- pack:
			return true
		case <-c.chdown:
		}
	}
	return false
}

func goconn(nc net.Conn) *conn {
	c := &conn{
		id:     atomic.AddUint64(&nconnid, 1),
		c:      nc,
		chrq:   make(chan *Packet, connReadCap),
		chwq:   make(chan *Packet, connWriteCap),
		chdown: make(chan struct{}),
	}
	go c.readloop()
	go c.writeloop()
	return c
}
<|endoftext|>


<commit_before>/**
 * connection wrapper
 */

package tok

import (
	//	"log"
	"time"
)

type func_ping func() []byte

type connection struct {
	uid     interface{}
	adapter ConAdapter
	ticker  *time.Ticker
	ch      chan []byte
	ping    func_ping
}

type conState struct {
	con    *connection
	online bool
}

type ConAdapter interface {
	Read() ([]byte, error)
	Write([]byte) error
	Close()
}

func (conn *connection) read(chState chan<- *conState, chUp chan<- *frame) {
	for {
		b, err := conn.adapter.Read()
		if err != nil {
			//			log.Println("read err", err)
			chState <- &conState{con: conn, online: false}
			break
		}
		chUp <- &frame{uid: conn.uid, data: b}
	}
}

func (conn *connection) write(chState chan<- *conState) {
	for {
		select {
		case b := <-conn.ch:
			if b == nil {
				conn.ticker.Stop()
				conn.adapter.Close()
				return
			}
			//			log.Println("down msg for ", conn)
			conn.innerWrite(chState, b)
		case <-conn.ticker.C:
			b := conn.ping()
			if b != nil {
				conn.innerWrite(chState, conn.ping())
			}
		}
	}

}

func (conn *connection) innerWrite(chState chan<- *conState, b []byte) {
	if err := conn.adapter.Write(b); err != nil {
		chState <- &conState{con: conn, online: false}
	}
}

func (conn *connection) close() {
	//	log.Println("close down channel", conn)
	close(conn.ch)
}

//block on read
func initConnection(uid interface{}, adapter ConAdapter, hub *Hub) {
	//	log.Println("new conection ", uid)

	conn := &connection{
		uid:     uid,
		adapter: adapter,
		ch:      make(chan []byte, 256),
		ticker:  time.NewTicker(30 * 1e9),
		ping:    hub.actor.Ping,
	}

	hub.chConState <- &conState{conn, true}
	go conn.write(hub.chConState)
	conn.read(hub.chConState, hub.chUp)
}
<commit_msg>minor refactor<commit_after>/**
 * connection wrapper
 */

package tok

import (
	//	"log"
	"time"
)

type func_ping func() []byte

type connection struct {
	uid     interface{}
	adapter ConAdapter
	ticker  *time.Ticker
	ch      chan []byte
	actor   Actor
}

type conState struct {
	con    *connection
	online bool
}

type ConAdapter interface {
	Read() ([]byte, error)
	Write([]byte) error
	Close()
}

func (conn *connection) read(chState chan<- *conState, chUp chan<- *frame) {
	for {
		b, err := conn.adapter.Read()
		if err != nil {
			//			log.Println("read err", err)
			chState <- &conState{con: conn, online: false}
			break
		}
		chUp <- &frame{uid: conn.uid, data: b}
	}
}

func (conn *connection) write(chState chan<- *conState) {
	for {
		select {
		case b := <-conn.ch:
			if b == nil {
				conn.ticker.Stop()
				conn.adapter.Close()
				return
			}
			//			log.Println("down msg for ", conn)
			conn.innerWrite(chState, b)
		case <-conn.ticker.C:
			if b := conn.actor.Ping(); b != nil {
				conn.innerWrite(chState, b)
			}
		}
	}

}

func (conn *connection) innerWrite(chState chan<- *conState, b []byte) {
	if err := conn.adapter.Write(b); err != nil {
		chState <- &conState{con: conn, online: false}
	}
}

func (conn *connection) close() {
	//	log.Println("close down channel", conn)
	close(conn.ch)
}

//block on read
func initConnection(uid interface{}, adapter ConAdapter, hub *Hub) {
	//	log.Println("new conection ", uid)

	conn := &connection{
		uid:     uid,
		adapter: adapter,
		ch:      make(chan []byte, 256),
		ticker:  time.NewTicker(30 * 1e9),
		actor:    hub.actor,
	}

	hub.chConState <- &conState{conn, true}
	go conn.write(hub.chConState)
	conn.read(hub.chConState, hub.chUp)
}
<|endoftext|>


<commit_before>package testdb

import (
	"database/sql/driver"
	"errors"
)

type conn struct {
	queries      map[string]query
	queryFunc    func(query string, args []driver.Value) (driver.Rows, error)
	execFunc     func(query string, args []driver.Value) (driver.Result, error)
	beginFunc    func() (driver.Tx, error)
	commitFunc   func() error
	rollbackFunc func() error
}

func newConn() *conn {
	return &conn{
		queries: make(map[string]query),
	}
}

func (c *conn) Prepare(query string) (driver.Stmt, error) {
	s := new(stmt)

	if c.queryFunc != nil {
		s.queryFunc = func(args []driver.Value) (driver.Rows, error) {
			return c.queryFunc(query, args)
		}
	}

	if c.execFunc != nil {
		s.execFunc = func(args []driver.Value) (driver.Result, error) {
			return c.execFunc(query, args)
		}
	}

	if q, ok := d.conn.queries[getQueryHash(query)]; ok {
		if s.queryFunc == nil && q.rows != nil {
			s.queryFunc = func(args []driver.Value) (driver.Rows, error) {
				if q.rows != nil {
					if rows, ok := q.rows.(*rows); ok {
						return rows.clone(), nil
					}
					return q.rows, nil
				}
				return nil, q.err
			}
		}

		if s.execFunc == nil && q.result != nil {
			s.execFunc = func(args []driver.Value) (driver.Result, error) {
				if q.result != nil {
					return q.result, nil
				}
				return nil, q.err
			}
		}
	}

	if !(s.queryFunc == nil || s.execFunc == nil) {
		return new(stmt), errors.New("Query not stubbed: " + query)
	}

	return s, nil
}

func (*conn) Close() error {
	return nil
}

func (c *conn) Begin() (driver.Tx, error) {
	if c.beginFunc != nil {
		return c.beginFunc()
	}

	t := &Tx{}
	if c.commitFunc != nil {
		t.SetCommitFunc(c.commitFunc)
	}
	if c.rollbackFunc != nil {
		t.SetRollbackFunc(c.rollbackFunc)
	}

	return t, nil
}

func (c *conn) Query(query string, args []driver.Value) (driver.Rows, error) {
	if c.queryFunc != nil {
		return c.queryFunc(query, args)
	}
	if q, ok := d.conn.queries[getQueryHash(query)]; ok {
		if rows, ok := q.rows.(*rows); ok {
			return rows.clone(), q.err
		}
		return q.rows, q.err
	}
	return nil, errors.New("Query not stubbed: " + query)
}

func (c *conn) Exec(query string, args []driver.Value) (driver.Result, error) {
	if c.execFunc != nil {
		return c.execFunc(query, args)
	}

	if q, ok := d.conn.queries[getQueryHash(query)]; ok {
		if q.result != nil {
			return q.result, nil
		} else if q.err != nil {
			return nil, q.err
		}
	}

	return nil, errors.New("Exec call not stubbed: " + query)
}
<commit_msg>Fix logic in implementation of Prepare()<commit_after>package testdb

import (
	"database/sql/driver"
	"errors"
)

type conn struct {
	queries      map[string]query
	queryFunc    func(query string, args []driver.Value) (driver.Rows, error)
	execFunc     func(query string, args []driver.Value) (driver.Result, error)
	beginFunc    func() (driver.Tx, error)
	commitFunc   func() error
	rollbackFunc func() error
}

func newConn() *conn {
	return &conn{
		queries: make(map[string]query),
	}
}

func (c *conn) Prepare(query string) (driver.Stmt, error) {
	s := new(stmt)

	if c.queryFunc != nil {
		s.queryFunc = func(args []driver.Value) (driver.Rows, error) {
			return c.queryFunc(query, args)
		}
	}

	if c.execFunc != nil {
		s.execFunc = func(args []driver.Value) (driver.Result, error) {
			return c.execFunc(query, args)
		}
	}

	if q, ok := d.conn.queries[getQueryHash(query)]; ok {
		if s.queryFunc == nil && q.rows != nil {
			s.queryFunc = func(args []driver.Value) (driver.Rows, error) {
				if q.rows != nil {
					if rows, ok := q.rows.(*rows); ok {
						return rows.clone(), nil
					}
					return q.rows, nil
				}
				return nil, q.err
			}
		}

		if s.execFunc == nil && q.result != nil {
			s.execFunc = func(args []driver.Value) (driver.Result, error) {
				if q.result != nil {
					return q.result, nil
				}
				return nil, q.err
			}
		}
	}

	if s.queryFunc == nil && s.execFunc == nil {
		return new(stmt), errors.New("Query not stubbed: " + query)
	}

	return s, nil
}

func (*conn) Close() error {
	return nil
}

func (c *conn) Begin() (driver.Tx, error) {
	if c.beginFunc != nil {
		return c.beginFunc()
	}

	t := &Tx{}
	if c.commitFunc != nil {
		t.SetCommitFunc(c.commitFunc)
	}
	if c.rollbackFunc != nil {
		t.SetRollbackFunc(c.rollbackFunc)
	}

	return t, nil
}

func (c *conn) Query(query string, args []driver.Value) (driver.Rows, error) {
	if c.queryFunc != nil {
		return c.queryFunc(query, args)
	}
	if q, ok := d.conn.queries[getQueryHash(query)]; ok {
		if rows, ok := q.rows.(*rows); ok {
			return rows.clone(), q.err
		}
		return q.rows, q.err
	}
	return nil, errors.New("Query not stubbed: " + query)
}

func (c *conn) Exec(query string, args []driver.Value) (driver.Result, error) {
	if c.execFunc != nil {
		return c.execFunc(query, args)
	}

	if q, ok := d.conn.queries[getQueryHash(query)]; ok {
		if q.result != nil {
			return q.result, nil
		} else if q.err != nil {
			return nil, q.err
		}
	}

	return nil, errors.New("Exec call not stubbed: " + query)
}
<|endoftext|>


<commit_before>package canopus

import (
	"log"
	"net"
	"sync"
)

func MessageSizeAllowed(req Request) bool {
	msg := req.GetMessage()
	b, _ := MessageToBytes(msg)

	if len(b) > 65536 {
		return false
	}

	return true
}

type UDPConnection struct {
	conn net.Conn
}

func (c *UDPConnection) ObserveResource(resource string) (tok string, err error) {
	req := NewRequest(MessageConfirmable, Get)
	req.SetRequestURI(resource)
	req.GetMessage().AddOption(OptionObserve, 0)

	resp, err := c.Send(req)
	tok = string(resp.GetMessage().GetToken())

	return
}

func (c *UDPConnection) CancelObserveResource(resource string, token string) (err error) {
	req := NewRequest(MessageConfirmable, Get)
	req.SetRequestURI(resource)
	req.GetMessage().AddOption(OptionObserve, 1)

	_, err = c.Send(req)
	return
}

func (c *UDPConnection) StopObserve(ch chan ObserveMessage) {
	close(ch)
}

func (c *UDPConnection) Close() error {
	return c.conn.Close()
}

func (c *UDPConnection) Observe(ch chan ObserveMessage) {

	readBuf := make([]byte, MaxPacketSize)
	for {
		len, err := c.Read(readBuf)
		if err == nil {
			msgBuf := make([]byte, len)
			copy(msgBuf, readBuf)

			msg, err := BytesToMessage(msgBuf)
			if msg.GetOption(OptionObserve) != nil {
				ch <- NewObserveMessage(msg.GetURIPath(), msg.GetPayload(), msg)
			}
			if err != nil {
				log.Println("Error occured reading UDP", err)
				close(ch)
			}
		} else {
			log.Println("Error occured reading UDP", err)
			close(ch)
		}
	}
}

func (c *UDPConnection) Send(req Request) (resp Response, err error) {
	msg := req.GetMessage()
	opt := msg.GetOption(OptionBlock1)

	if opt == nil { // Block1 was not set
		if MessageSizeAllowed(req) != true {
			return nil, ErrMessageSizeTooLongBlockOptionValNotSet
		}
	} else { // Block1 was set
		// log.Println("Block 1 was set")
	}

	if opt != nil {
		blockOpt := Block1OptionFromOption(opt)
		if blockOpt.Value == nil {
			if MessageSizeAllowed(req) != true {
				err = ErrMessageSizeTooLongBlockOptionValNotSet
				return
			} else {
				// - Block # = one and only block (sz = unspecified), whereas 0 = 16bits
				// - MOre bit = 0
			}
		} else { // BLock transfer request
			payload := msg.GetPayload().GetBytes()
			payloadLen := uint32(len(payload))
			blockSize := blockOpt.BlockSizeLength()
			currSeq := uint32(0)
			totalBlocks := uint32(payloadLen / blockSize)
			completed := false

			var wg sync.WaitGroup
			wg.Add(1)

			for completed == false {
				if currSeq <= totalBlocks {

					var blockPayloadStart uint32
					var blockPayloadEnd uint32
					var blockPayload []byte

					blockPayloadStart = currSeq*uint32(blockSize) + (currSeq * 1)

					more := true
					if currSeq == totalBlocks {
						more = false
						blockPayloadEnd = payloadLen
					} else {
						blockPayloadEnd = blockPayloadStart + uint32(blockSize)
					}

					blockPayload = payload[blockPayloadStart : blockPayloadEnd+1]

					blockOpt = NewBlock1Option(blockOpt.Size(), more, currSeq)
					msg.ReplaceOptions(blockOpt.Code, []Option{blockOpt})
					modifiedMsg := msg.(*CoapMessage)
					modifiedMsg.SetMessageId(GenerateMessageID())
					modifiedMsg.SetPayload(NewBytesPayload(blockPayload))

					// send message
					_, err2 := c.SendMessage(msg)
					if err2 != nil {
						wg.Done()
						return
					}
					currSeq = currSeq + 1

				} else {
					completed = true
					wg.Done()
				}
			}
		}
	}
	resp, err = c.SendMessage(msg)
	return
}

func (c *UDPConnection) SendMessage(msg Message) (resp Response, err error) {
	if msg == nil {
		return nil, ErrNilMessage
	}

	b, err := MessageToBytes(msg)
	if err != nil {
		return
	}

	if msg.GetMessageType() == MessageNonConfirmable {
		go c.Write(b)
		resp = NewResponse(NewEmptyMessage(msg.GetMessageId()), nil)
		return
	}

	_, err = c.Write(b)
	if err != nil {
		return
	}

	msgBuf := make([]byte, 1500)
	if msg.GetMessageType() == MessageAcknowledgment {
		resp = NewResponse(NewEmptyMessage(msg.GetMessageId()), nil)
		return
	}

	n, err := c.Read(msgBuf)
	if err != nil {
		return
	}

	respMsg, err := BytesToMessage(msgBuf[:n])
	if err != nil {
		return
	}
	resp = NewResponse(respMsg, nil)

	if msg.GetMessageType() == MessageConfirmable {
		// TODO: Send out message and wait for a confirm. If confirmation not retrieved,
		// resend (taking into account timeouts and back-off transmissions

		// c.Send(NewRequestFromMessage(msg))
	}
	return
}

func (c *UDPConnection) Write(b []byte) (int, error) {
	return c.conn.Write(b)
}

func (c *UDPConnection) Read(b []byte) (int, error) {
	return c.conn.Read(b)
}
<commit_msg>calculate blockPayloadStart wrong when send blocks<commit_after>package canopus

import (
	"log"
	"net"
	"sync"
)

func MessageSizeAllowed(req Request) bool {
	msg := req.GetMessage()
	b, _ := MessageToBytes(msg)

	if len(b) > 65536 {
		return false
	}

	return true
}

type UDPConnection struct {
	conn net.Conn
}

func (c *UDPConnection) ObserveResource(resource string) (tok string, err error) {
	req := NewRequest(MessageConfirmable, Get)
	req.SetRequestURI(resource)
	req.GetMessage().AddOption(OptionObserve, 0)

	resp, err := c.Send(req)
	tok = string(resp.GetMessage().GetToken())

	return
}

func (c *UDPConnection) CancelObserveResource(resource string, token string) (err error) {
	req := NewRequest(MessageConfirmable, Get)
	req.SetRequestURI(resource)
	req.GetMessage().AddOption(OptionObserve, 1)

	_, err = c.Send(req)
	return
}

func (c *UDPConnection) StopObserve(ch chan ObserveMessage) {
	close(ch)
}

func (c *UDPConnection) Close() error {
	return c.conn.Close()
}

func (c *UDPConnection) Observe(ch chan ObserveMessage) {

	readBuf := make([]byte, MaxPacketSize)
	for {
		len, err := c.Read(readBuf)
		if err == nil {
			msgBuf := make([]byte, len)
			copy(msgBuf, readBuf)

			msg, err := BytesToMessage(msgBuf)
			if msg.GetOption(OptionObserve) != nil {
				ch <- NewObserveMessage(msg.GetURIPath(), msg.GetPayload(), msg)
			}
			if err != nil {
				log.Println("Error occured reading UDP", err)
				close(ch)
			}
		} else {
			log.Println("Error occured reading UDP", err)
			close(ch)
		}
	}
}

func (c *UDPConnection) Send(req Request) (resp Response, err error) {
	msg := req.GetMessage()
	opt := msg.GetOption(OptionBlock1)

	if opt == nil { // Block1 was not set
		if MessageSizeAllowed(req) != true {
			return nil, ErrMessageSizeTooLongBlockOptionValNotSet
		}
	} else { // Block1 was set
		// log.Println("Block 1 was set")
	}

	if opt != nil {
		blockOpt := Block1OptionFromOption(opt)
		if blockOpt.Value == nil {
			if MessageSizeAllowed(req) != true {
				err = ErrMessageSizeTooLongBlockOptionValNotSet
				return
			} else {
				// - Block # = one and only block (sz = unspecified), whereas 0 = 16bits
				// - MOre bit = 0
			}
		} else { // BLock transfer request
			payload := msg.GetPayload().GetBytes()
			payloadLen := uint32(len(payload))
			blockSize := blockOpt.BlockSizeLength()
			currSeq := uint32(0)
			totalBlocks := uint32(payloadLen / blockSize)
			completed := false

			var wg sync.WaitGroup
			wg.Add(1)

			for completed == false {
				if currSeq <= totalBlocks {

					var blockPayloadStart uint32
					var blockPayloadEnd uint32
					var blockPayload []byte

					blockPayloadStart = currSeq * uint32(blockSize)

					more := true
					if currSeq == totalBlocks {
						more = false
						blockPayloadEnd = payloadLen
					} else {
						blockPayloadEnd = blockPayloadStart + uint32(blockSize)
					}

					blockPayload = payload[blockPayloadStart : blockPayloadEnd+1]

					blockOpt = NewBlock1Option(blockOpt.Size(), more, currSeq)
					msg.ReplaceOptions(blockOpt.Code, []Option{blockOpt})
					modifiedMsg := msg.(*CoapMessage)
					modifiedMsg.SetMessageId(GenerateMessageID())
					modifiedMsg.SetPayload(NewBytesPayload(blockPayload))

					// send message
					_, err2 := c.SendMessage(msg)
					if err2 != nil {
						wg.Done()
						return
					}
					currSeq = currSeq + 1

				} else {
					completed = true
					wg.Done()
				}
			}
		}
	}
	resp, err = c.SendMessage(msg)
	return
}

func (c *UDPConnection) SendMessage(msg Message) (resp Response, err error) {
	if msg == nil {
		return nil, ErrNilMessage
	}

	b, err := MessageToBytes(msg)
	if err != nil {
		return
	}

	if msg.GetMessageType() == MessageNonConfirmable {
		go c.Write(b)
		resp = NewResponse(NewEmptyMessage(msg.GetMessageId()), nil)
		return
	}

	_, err = c.Write(b)
	if err != nil {
		return
	}

	msgBuf := make([]byte, 1500)
	if msg.GetMessageType() == MessageAcknowledgment {
		resp = NewResponse(NewEmptyMessage(msg.GetMessageId()), nil)
		return
	}

	n, err := c.Read(msgBuf)
	if err != nil {
		return
	}

	respMsg, err := BytesToMessage(msgBuf[:n])
	if err != nil {
		return
	}
	resp = NewResponse(respMsg, nil)

	if msg.GetMessageType() == MessageConfirmable {
		// TODO: Send out message and wait for a confirm. If confirmation not retrieved,
		// resend (taking into account timeouts and back-off transmissions

		// c.Send(NewRequestFromMessage(msg))
	}
	return
}

func (c *UDPConnection) Write(b []byte) (int, error) {
	return c.conn.Write(b)
}

func (c *UDPConnection) Read(b []byte) (int, error) {
	return c.conn.Read(b)
}
<|endoftext|>


<commit_before>// Copyright 2015 The Mangos Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use 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 mangos

import (
	"encoding/binary"
	"io"
	"net"
	"sync"
)

// conn implements the Pipe interface on top of net.Conn.  The
// assumption is that transports using this have similar wire protocols,
// and conn is meant to be used as a building block.
type conn struct {
	c      net.Conn
	rlock  sync.Mutex
	wlock  sync.Mutex
	rproto uint16
	lproto uint16
	open   bool
}

// connipc is *almost* like a regular conn, but the IPC protocol insists
// on stuffing a leading byte (valued 1) in front of messages.  This is for
// compatibility with nanomsg -- the value cannot ever be anything but 1.
type connipc struct {
	conn
}

// Recv implements the Pipe Recv method.  The message received is expected as
// a 64-bit size (network byte order) followed by the message itself.
func (p *conn) Recv() (*Message, error) {

	var sz int64
	var err error
	var msg *Message

	// prevent interleaved reads
	p.rlock.Lock()
	defer p.rlock.Unlock()

	if err = binary.Read(p.c, binary.BigEndian, &sz); err != nil {
		return nil, err
	}

	// TBD: This fixed limit is kind of silly, but it keeps
	// a bogus peer from causing us to try to allocate ridiculous
	// amounts of memory.  If you don't like it, then prealloc
	// a buffer.  But for protocols that only use small messages
	// this can actually be more efficient since we don't allocate
	// any more space than our peer says we need to.
	if sz > 1024*1024 || sz < 0 {
		p.c.Close()
		return nil, ErrTooLong
	}
	msg = NewMessage(int(sz))
	msg.Body = msg.Body[0:sz]
	if _, err = io.ReadFull(p.c, msg.Body); err != nil {
		msg.Free()
		return nil, err
	}
	return msg, nil
}

// Send implements the Pipe Send method.  The message is sent as a 64-bit
// size (network byte order) followed by the message itself.
func (p *conn) Send(msg *Message) error {

	l := uint64(len(msg.Header) + len(msg.Body))

	// prevent interleaved writes
	p.wlock.Lock()
	defer p.wlock.Unlock()

	// send length header
	if err := binary.Write(p.c, binary.BigEndian, l); err != nil {
		return err
	}
	if _, err := p.c.Write(msg.Header); err != nil {
		return err
	}
	// hope this works
	if _, err := p.c.Write(msg.Body); err != nil {
		return err
	}
	msg.Free()
	return nil
}

// LocalProtocol returns our local protocol number.
func (p *conn) LocalProtocol() uint16 {
	return p.lproto
}

// RemoteProtocol returns our peer's protocol number.
func (p *conn) RemoteProtocol() uint16 {
	return p.rproto
}

// Close implements the Pipe Close method.
func (p *conn) Close() error {
	p.open = false
	return p.c.Close()
}

// IsOpen implements the PipeIsOpen method.
func (p *conn) IsOpen() bool {
	return p.open
}

// NewConnPipe allocates a new Pipe using the supplied net.Conn, and
// initializes it.  It performs the handshake required at the SP layer,
// only returning the Pipe once the SP layer negotiation is complete.
//
// Stream oriented transports can utilize this to implement a Transport.
// The implementation will also need to implement PipeDialer, PipeAccepter,
// and the Transport enclosing structure.   Using this layered interface,
// the implementation needn't bother concerning itself with passing actual
// SP messages once the lower layer connection is established.
func NewConnPipe(c net.Conn, lproto uint16) (Pipe, error) {
	p := &conn{c: c, lproto: lproto}
	if err := p.handshake(); err != nil {
		return nil, err
	}

	return p, nil
}

// NewConnPipeIPC allocates a new Pipe using the IPC exchange protocol.
func NewConnPipeIPC(c net.Conn, lproto uint16) (Pipe, error) {
	p := &connipc{}
	p.c = c
	p.lproto = lproto
	if err := p.handshake(); err != nil {
		return nil, err
	}

	return p, nil
}

func (p *connipc) Send(msg *Message) error {

	l := uint64(len(msg.Header) + len(msg.Body))
	one := [1]byte{1}
	var err error

	// prevent interleaved writes
	p.wlock.Lock()
	defer p.wlock.Unlock()
	defer msg.Free()

	// send length header
	if _, err = p.c.Write(one[:]); err != nil {
		return err
	}
	if err = binary.Write(p.c, binary.BigEndian, l); err != nil {
		return err
	}
	if _, err = p.c.Write(msg.Header); err != nil {
		return err
	}
	// hope this works
	if _, err = p.c.Write(msg.Body); err != nil {
		return err
	}
	return nil
}

func (p *connipc) Recv() (*Message, error) {

	var sz int64
	var err error
	var msg *Message
	var one [1]byte

	// prevent interleaved reads
	p.rlock.Lock()
	defer p.rlock.Unlock()

	if _, err = p.c.Read(one[:]); err != nil {
		return nil, err
	}
	if err = binary.Read(p.c, binary.BigEndian, &sz); err != nil {
		return nil, err
	}

	// TBD: This fixed limit is kind of silly, but it keeps
	// a bogus peer from causing us to try to allocate ridiculous
	// amounts of memory.  If you don't like it, then prealloc
	// a buffer.  But for protocols that only use small messages
	// this can actually be more efficient since we don't allocate
	// any more space than our peer says we need to.
	if sz > 1024*1024 || sz < 0 {
		p.c.Close()
		return nil, ErrTooLong
	}
	msg = NewMessage(int(sz))
	msg.Body = msg.Body[0:sz]
	if _, err = io.ReadFull(p.c, msg.Body); err != nil {
		msg.Free()
		return nil, err
	}
	return msg, nil
}

// connHeader is exchanged during the initial handshake.
type connHeader struct {
	Zero    byte // must be zero
	S       byte // 'S'
	P       byte // 'P'
	Version byte // only zero at present
	Proto   uint16
	Rsvd    uint16 // always zero at present
}

// handshake establishes an SP connection between peers.  Both sides must
// send the header, then both sides must wait for the peer's header.
// As a side effect, the peer's protocol number is stored in the conn.
func (p *conn) handshake() error {
	var err error

	h := connHeader{S: 'S', P: 'P', Proto: p.lproto}
	if err = binary.Write(p.c, binary.BigEndian, &h); err != nil {
		return err
	}
	if err = binary.Read(p.c, binary.BigEndian, &h); err != nil {
		p.c.Close()
		return err
	}
	if h.Zero != 0 || h.S != 'S' || h.P != 'P' || h.Rsvd != 0 {
		p.c.Close()
		return ErrBadHeader
	}
	// The only version number we support at present is "0", at offset 3.
	if h.Version != 0 {
		p.c.Close()
		return ErrBadVersion
	}

	// The protocol number lives as 16-bits (big-endian) at offset 4.
	p.rproto = h.Proto
	p.open = true
	return nil
}
<commit_msg>Fixes #44 Another duplicate free during SendMsg error<commit_after>// Copyright 2015 The Mangos Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use 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 mangos

import (
	"encoding/binary"
	"io"
	"net"
	"sync"
)

// conn implements the Pipe interface on top of net.Conn.  The
// assumption is that transports using this have similar wire protocols,
// and conn is meant to be used as a building block.
type conn struct {
	c      net.Conn
	rlock  sync.Mutex
	wlock  sync.Mutex
	rproto uint16
	lproto uint16
	open   bool
}

// connipc is *almost* like a regular conn, but the IPC protocol insists
// on stuffing a leading byte (valued 1) in front of messages.  This is for
// compatibility with nanomsg -- the value cannot ever be anything but 1.
type connipc struct {
	conn
}

// Recv implements the Pipe Recv method.  The message received is expected as
// a 64-bit size (network byte order) followed by the message itself.
func (p *conn) Recv() (*Message, error) {

	var sz int64
	var err error
	var msg *Message

	// prevent interleaved reads
	p.rlock.Lock()
	defer p.rlock.Unlock()

	if err = binary.Read(p.c, binary.BigEndian, &sz); err != nil {
		return nil, err
	}

	// TBD: This fixed limit is kind of silly, but it keeps
	// a bogus peer from causing us to try to allocate ridiculous
	// amounts of memory.  If you don't like it, then prealloc
	// a buffer.  But for protocols that only use small messages
	// this can actually be more efficient since we don't allocate
	// any more space than our peer says we need to.
	if sz > 1024*1024 || sz < 0 {
		p.c.Close()
		return nil, ErrTooLong
	}
	msg = NewMessage(int(sz))
	msg.Body = msg.Body[0:sz]
	if _, err = io.ReadFull(p.c, msg.Body); err != nil {
		msg.Free()
		return nil, err
	}
	return msg, nil
}

// Send implements the Pipe Send method.  The message is sent as a 64-bit
// size (network byte order) followed by the message itself.
func (p *conn) Send(msg *Message) error {

	l := uint64(len(msg.Header) + len(msg.Body))

	// prevent interleaved writes
	p.wlock.Lock()
	defer p.wlock.Unlock()

	// send length header
	if err := binary.Write(p.c, binary.BigEndian, l); err != nil {
		return err
	}
	if _, err := p.c.Write(msg.Header); err != nil {
		return err
	}
	// hope this works
	if _, err := p.c.Write(msg.Body); err != nil {
		return err
	}
	msg.Free()
	return nil
}

// LocalProtocol returns our local protocol number.
func (p *conn) LocalProtocol() uint16 {
	return p.lproto
}

// RemoteProtocol returns our peer's protocol number.
func (p *conn) RemoteProtocol() uint16 {
	return p.rproto
}

// Close implements the Pipe Close method.
func (p *conn) Close() error {
	p.open = false
	return p.c.Close()
}

// IsOpen implements the PipeIsOpen method.
func (p *conn) IsOpen() bool {
	return p.open
}

// NewConnPipe allocates a new Pipe using the supplied net.Conn, and
// initializes it.  It performs the handshake required at the SP layer,
// only returning the Pipe once the SP layer negotiation is complete.
//
// Stream oriented transports can utilize this to implement a Transport.
// The implementation will also need to implement PipeDialer, PipeAccepter,
// and the Transport enclosing structure.   Using this layered interface,
// the implementation needn't bother concerning itself with passing actual
// SP messages once the lower layer connection is established.
func NewConnPipe(c net.Conn, lproto uint16) (Pipe, error) {
	p := &conn{c: c, lproto: lproto}
	if err := p.handshake(); err != nil {
		return nil, err
	}

	return p, nil
}

// NewConnPipeIPC allocates a new Pipe using the IPC exchange protocol.
func NewConnPipeIPC(c net.Conn, lproto uint16) (Pipe, error) {
	p := &connipc{}
	p.c = c
	p.lproto = lproto
	if err := p.handshake(); err != nil {
		return nil, err
	}

	return p, nil
}

func (p *connipc) Send(msg *Message) error {

	l := uint64(len(msg.Header) + len(msg.Body))
	one := [1]byte{1}
	var err error

	// prevent interleaved writes
	p.wlock.Lock()
	defer p.wlock.Unlock()

	// send length header
	if _, err = p.c.Write(one[:]); err != nil {
		return err
	}
	if err = binary.Write(p.c, binary.BigEndian, l); err != nil {
		return err
	}
	if _, err = p.c.Write(msg.Header); err != nil {
		return err
	}
	// hope this works
	if _, err = p.c.Write(msg.Body); err != nil {
		return err
	}
	msg.Free()
	return nil
}

func (p *connipc) Recv() (*Message, error) {

	var sz int64
	var err error
	var msg *Message
	var one [1]byte

	// prevent interleaved reads
	p.rlock.Lock()
	defer p.rlock.Unlock()

	if _, err = p.c.Read(one[:]); err != nil {
		return nil, err
	}
	if err = binary.Read(p.c, binary.BigEndian, &sz); err != nil {
		return nil, err
	}

	// TBD: This fixed limit is kind of silly, but it keeps
	// a bogus peer from causing us to try to allocate ridiculous
	// amounts of memory.  If you don't like it, then prealloc
	// a buffer.  But for protocols that only use small messages
	// this can actually be more efficient since we don't allocate
	// any more space than our peer says we need to.
	if sz > 1024*1024 || sz < 0 {
		p.c.Close()
		return nil, ErrTooLong
	}
	msg = NewMessage(int(sz))
	msg.Body = msg.Body[0:sz]
	if _, err = io.ReadFull(p.c, msg.Body); err != nil {
		msg.Free()
		return nil, err
	}
	return msg, nil
}

// connHeader is exchanged during the initial handshake.
type connHeader struct {
	Zero    byte // must be zero
	S       byte // 'S'
	P       byte // 'P'
	Version byte // only zero at present
	Proto   uint16
	Rsvd    uint16 // always zero at present
}

// handshake establishes an SP connection between peers.  Both sides must
// send the header, then both sides must wait for the peer's header.
// As a side effect, the peer's protocol number is stored in the conn.
func (p *conn) handshake() error {
	var err error

	h := connHeader{S: 'S', P: 'P', Proto: p.lproto}
	if err = binary.Write(p.c, binary.BigEndian, &h); err != nil {
		return err
	}
	if err = binary.Read(p.c, binary.BigEndian, &h); err != nil {
		p.c.Close()
		return err
	}
	if h.Zero != 0 || h.S != 'S' || h.P != 'P' || h.Rsvd != 0 {
		p.c.Close()
		return ErrBadHeader
	}
	// The only version number we support at present is "0", at offset 3.
	if h.Version != 0 {
		p.c.Close()
		return ErrBadVersion
	}

	// The protocol number lives as 16-bits (big-endian) at offset 4.
	p.rproto = h.Proto
	p.open = true
	return nil
}
<|endoftext|>


<commit_before>// Cook generate projects from templates based on github repositories.
package main

import (
	"bufio"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strings"
)

var regex, _ = regexp.Compile("{{(\\s|)cook?\\w+\\.\\w+(\\s|)}}")

// Clone fetch a git repository to current directory and returns a directory name
func Clone(repoName string) string {
	repoURL := "git@github.com:" + repoName + ".git"

	cloneCmd := exec.Command("git", "clone", repoURL)
	_, err := cloneCmd.Output()

	if err != nil {
		panic(err)
	}

	return strings.Split(repoName, "/")[1]
}

// Parse a json config file to ask user to new values
func Parse(repoPath string) map[string]interface{} {
	var configJson map[string]interface{}
	configNames := [2]string{"cook.json", "cookiecutter.json"}

	for index := range configNames {
		config, err := ioutil.ReadFile(repoPath + string(os.PathSeparator) + configNames[index])

		if err != nil {
			continue
		}

		json.Unmarshal([]byte(config), &configJson)
	}

	if len(configJson) == 0 {
		panic("This is not a valid repository.")
	}

	return configJson
}

// Ask receive a config map, iterate over and update user project data
func Ask(config map[string]interface{}) map[string]interface{} {
	for k, v := range config {
		reader := bufio.NewReader(os.Stdin)
		fmt.Print("Enter ", k, " (default: ", v, "): ")
		text, _ := reader.ReadString('\n')

		if len(strings.TrimSpace(text)) > 0 {
			text = strings.TrimSuffix(text, "\n")
			config[k] = text
		}
	}

	return config
}

// getKey receive a string with a placeholder, parse and return a key string
func getKey(placeholder string) string {
	placeholder = regex.FindString(placeholder)
	strParts := strings.Split(placeholder, ".")[1]

	key := strings.Replace(strParts, "}}", "", -1)
	key = strings.TrimSpace(key)
	return key
}

// getPaths receive a repository path and returns a slice with template files/dirs path
func getPaths(repoPath string) []string {
	var paths = make([]string, 0)

	filepath.Walk(repoPath, func(fp string, fi os.FileInfo, err error) error {
		if err != nil {
			fmt.Println(err) // can't walk here,
			return nil       // but continue walking elsewhere
		}

		matched := regex.MatchString(fi.Name())

		if matched {
			paths = append(paths, fp)
		}

		return nil
	})

	return paths
}

// ReplacePaths receives a slices of paths and a config map to replace
// variables with config values
func ReplacePaths(paths []string, config map[string]interface{}) string {
	var newFolder string

	// reverse paths list to rename files/dirs without lost references
	for i := len(paths) - 1; i >= 0; i-- {
		parts := strings.Split(paths[i], string(os.PathSeparator))
		replacePart := parts[len(parts)-1]
		originalPart := parts[len(parts)-1]

		key := getKey(replacePart)
		value := config[key].(string)

		originalPart = regex.ReplaceAllString(originalPart, value)
		parts[len(parts)-1] = originalPart
		newPath := strings.Join(parts, string(os.PathSeparator))

		os.Rename(paths[i], newPath)

		if i == 0 {
			folderParts := strings.Split(newPath, string(os.PathSeparator))
			oldFolder := folderParts[0]
			newFolder = folderParts[1]

			os.Rename(newPath, newFolder)
			os.RemoveAll(oldFolder)
		}
	}
	return newFolder
}

//ReplaceContent receives a config map to replace all files with your variables
func ReplaceContent(repoPath string, config map[string]interface{}) {
	filepath.Walk(repoPath, func(fp string, fi os.FileInfo, err error) error {
		if err != nil {
			fmt.Println(err) // can't walk here,
			return nil       // but continue walking elsewhere
		}

		if !!fi.IsDir() {
			return nil // not a file.  ignore.
		}

		file, err := ioutil.ReadFile(fp)
		if err != nil {
			fmt.Println(err)
		}

		lines := strings.Split(string(file), "\n")
		for i, line := range lines {
			placeholders := regex.FindAllString(line, -1)
			for _, ph := range placeholders {
				key := getKey(ph)
				value := config[key].(string)
				fmt.Println(key, value)
				lines[i] = strings.Replace(lines[i], ph, value, 1)
			}
		}
		output := strings.Join(lines, "\n")
		err = ioutil.WriteFile(fp, []byte(output), 0644)
		if err != nil {
			fmt.Println(err)
		}

		return nil
	})
}

func main() {
	var repoName, repoPath string

	if len(os.Args) > 1 {
		repoName = os.Args[1]
	} else {
		fmt.Println("You must provide a github <username>/<repository>")
		return
	}

	repoPath = Clone(repoName)
	config := Parse(repoPath)
	config = Ask(config)

	paths := getPaths(repoPath)
	repoPath = ReplacePaths(paths, config)
	ReplaceContent(repoPath, config)
	fmt.Println("Project genereated: ", repoPath)
}
<commit_msg>remove println<commit_after>// Cook generate projects from templates based on github repositories.
package main

import (
	"bufio"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strings"
)

var regex, _ = regexp.Compile("{{(\\s|)cook?\\w+\\.\\w+(\\s|)}}")

// Clone fetch a git repository to current directory and returns a directory name
func Clone(repoName string) string {
	repoURL := "git@github.com:" + repoName + ".git"

	cloneCmd := exec.Command("git", "clone", repoURL)
	_, err := cloneCmd.Output()

	if err != nil {
		panic(err)
	}

	return strings.Split(repoName, "/")[1]
}

// Parse a json config file to ask user to new values
func Parse(repoPath string) map[string]interface{} {
	var configJson map[string]interface{}
	configNames := [2]string{"cook.json", "cookiecutter.json"}

	for index := range configNames {
		config, err := ioutil.ReadFile(repoPath + string(os.PathSeparator) + configNames[index])

		if err != nil {
			continue
		}

		json.Unmarshal([]byte(config), &configJson)
	}

	if len(configJson) == 0 {
		panic("This is not a valid repository.")
	}

	return configJson
}

// Ask receive a config map, iterate over and update user project data
func Ask(config map[string]interface{}) map[string]interface{} {
	for k, v := range config {
		reader := bufio.NewReader(os.Stdin)
		fmt.Print("Enter ", k, " (default: ", v, "): ")
		text, _ := reader.ReadString('\n')

		if len(strings.TrimSpace(text)) > 0 {
			text = strings.TrimSuffix(text, "\n")
			config[k] = text
		}
	}

	return config
}

// getKey receive a string with a placeholder, parse and return a key string
func getKey(placeholder string) string {
	placeholder = regex.FindString(placeholder)
	strParts := strings.Split(placeholder, ".")[1]

	key := strings.Replace(strParts, "}}", "", -1)
	key = strings.TrimSpace(key)
	return key
}

// getPaths receive a repository path and returns a slice with template files/dirs path
func getPaths(repoPath string) []string {
	var paths = make([]string, 0)

	filepath.Walk(repoPath, func(fp string, fi os.FileInfo, err error) error {
		if err != nil {
			fmt.Println(err) // can't walk here,
			return nil       // but continue walking elsewhere
		}

		matched := regex.MatchString(fi.Name())

		if matched {
			paths = append(paths, fp)
		}

		return nil
	})

	return paths
}

// ReplacePaths receives a slices of paths and a config map to replace
// variables with config values
func ReplacePaths(paths []string, config map[string]interface{}) string {
	var newFolder string

	// reverse paths list to rename files/dirs without lost references
	for i := len(paths) - 1; i >= 0; i-- {
		parts := strings.Split(paths[i], string(os.PathSeparator))
		replacePart := parts[len(parts)-1]
		originalPart := parts[len(parts)-1]

		key := getKey(replacePart)
		value := config[key].(string)

		originalPart = regex.ReplaceAllString(originalPart, value)
		parts[len(parts)-1] = originalPart
		newPath := strings.Join(parts, string(os.PathSeparator))

		os.Rename(paths[i], newPath)

		if i == 0 {
			folderParts := strings.Split(newPath, string(os.PathSeparator))
			oldFolder := folderParts[0]
			newFolder = folderParts[1]

			os.Rename(newPath, newFolder)
			os.RemoveAll(oldFolder)
		}
	}
	return newFolder
}

//ReplaceContent receives a config map to replace all files with your variables
func ReplaceContent(repoPath string, config map[string]interface{}) {
	filepath.Walk(repoPath, func(fp string, fi os.FileInfo, err error) error {
		if err != nil {
			fmt.Println(err) // can't walk here,
			return nil       // but continue walking elsewhere
		}

		if !!fi.IsDir() {
			return nil // not a file.  ignore.
		}

		file, err := ioutil.ReadFile(fp)
		if err != nil {
			fmt.Println(err)
		}

		lines := strings.Split(string(file), "\n")
		for i, line := range lines {
			placeholders := regex.FindAllString(line, -1)
			for _, ph := range placeholders {
				key := getKey(ph)
				value := config[key].(string)
				lines[i] = strings.Replace(lines[i], ph, value, 1)
			}
		}
		output := strings.Join(lines, "\n")
		err = ioutil.WriteFile(fp, []byte(output), 0644)
		if err != nil {
			fmt.Println(err)
		}

		return nil
	})
}

func main() {
	var repoName, repoPath string

	if len(os.Args) > 1 {
		repoName = os.Args[1]
	} else {
		fmt.Println("You must provide a github <username>/<repository>")
		return
	}

	repoPath = Clone(repoName)
	config := Parse(repoPath)
	config = Ask(config)

	paths := getPaths(repoPath)
	repoPath = ReplacePaths(paths, config)
	ReplaceContent(repoPath, config)
	fmt.Println("Project genereated: ", repoPath)
}
<|endoftext|>


<commit_before>package main

import (
	_ "bufio"
	"encoding/xml"
	"fmt"
	_ "io"
	"net"
)

type Query struct {
	XMLName  xml.Name `xml:"query"`
	Xmlns    string   `xml:"xmlns,attr"`
	Username string   `xml:"username"`
	Password string   `xml:"password"`
	Digest   string   `xml:"digest"`
	Resource string   `xml:"resource"`
}

type Iq struct {
	XMLName xml.Name `xml:"iq"`
	Type    string   `xml:"type,attr"`
	Id      string   `xml:"id,attr"`
	Query   Query    `xml:"query"`
}

type Stream struct {
	XMLName xml.Name `xml:"stream:stream"`
	Iq      Iq       `xml:"iq"`
}

type LoginReq struct {
	Iq Iq `xml:"iq"`
}

func Serve(addr string) {
	fmt.Println("Server started")
	ln, err := net.Listen("tcp", addr)
	if err != nil {
		// handle error
	}
	for {
		conn, err := ln.Accept()
		if err != nil {
			// handle error
			continue
		}
		go handleConnection(conn)
	}
}

func ParseIq(request string) (iq Iq, e error) {

	v := LoginReq{}

	err := xml.Unmarshal([]byte(request), &v)

	if err != nil {
		fmt.Printf("err: %v", err)
		return v.Iq, err
	}
	fmt.Printf("Id: %v\n", v.Iq.Id)
	return v.Iq, err
}

func Authenticate(username string, password string) (authXml string) {
	return "hey"
}

func handleConnection(conn net.Conn) {
	fmt.Printf("Handling connection....")

    b := xml.NewDecoder(conn)
	fmt.Fprintf(conn, `<?xml version='1.0'?>
		<stream:stream
			from='localhost'
			id='abc123'
			to='james@localhost'
			version='1.0'
			xml:lang='en'
			xmlns='jabber:server'
			xmlns:stream='http://etherx.jabber.org/streams'>`)

	fmt.Fprintf(conn, "<stream:features/>")
	for {
        iqData := new(Iq)
        b.Decode(iqData)

		switch iqData.Type {
		case "get":
            r := &Iq{Id: iqData.Id, Type: "result"}
			r.Query = Query{Xmlns: "jabber:iq:auth"}
			output, _ := xml.Marshal(r)
			fmt.Println(string(output))
			fmt.Fprintf(conn, string(output))
		case "set":
			fmt.Println("** Case Set **")
            i := Iq{Id: iqData.Id, Type: "result"}
			output2, _ := xml.Marshal(i)
			fmt.Println(string(output2))
			fmt.Fprintf(conn, string(output2))
		default:
			//fmt.Println(string(line))
		}
	}

}
<commit_msg>Cleanup<commit_after>package main

import (
	_ "bufio"
	"encoding/xml"
	"fmt"
	_ "io"
	"net"
)

type Query struct {
	XMLName  xml.Name `xml:"query"`
	Xmlns    string   `xml:"xmlns,attr"`
	Username string   `xml:"username"`
	Password string   `xml:"password"`
	Digest   string   `xml:"digest"`
	Resource string   `xml:"resource"`
}

type Iq struct {
	XMLName xml.Name `xml:"iq"`
	Type    string   `xml:"type,attr"`
	Id      string   `xml:"id,attr"`
	Query   Query    `xml:"query"`
}

type Stream struct {
	XMLName xml.Name `xml:"stream:stream"`
	Iq      Iq       `xml:"iq"`
}

type LoginReq struct {
	Iq Iq `xml:"iq"`
}

func Serve(addr string) {
	ln, err := net.Listen("tcp", addr)
	if err != nil {
		// handle error
	}
	for {
		conn, err := ln.Accept()
		if err != nil {
			// handle error
			continue
		}
		go handleConnection(conn)
	}
}

func handleConnection(conn net.Conn) {

    b := xml.NewDecoder(conn)
	fmt.Fprintf(conn, `<?xml version='1.0'?>
		<stream:stream
			from='localhost'
			id='abc123'
			to='james@localhost'
			version='1.0'
			xml:lang='en'
			xmlns='jabber:server'
			xmlns:stream='http://etherx.jabber.org/streams'>`)

	fmt.Fprintf(conn, "<stream:features/>")
	for {
        iqData := new(Iq)
        b.Decode(iqData)
		switch iqData.Type {
            case "get":
                r := &Iq{Id: iqData.Id, Type: "result"}
                r.Query = Query{Xmlns: "jabber:iq:auth"}
                output, _ := xml.Marshal(r)
                fmt.Fprintf(conn, string(output))
            case "set":
                // Need to perform auth lookup here
                i := Iq{Id: iqData.Id, Type: "result"}
                output, _ := xml.Marshal(i)
                fmt.Fprintf(conn, string(output))
            default:
                // Nothing
		}
	}

}
<|endoftext|>


<commit_before>package gohm

import (
	"fmt"
	"net/http"
	"regexp"
	"sort"
	"strings"
)

// CORSConfig holds parameters for configuring a CORSHandler.
type CORSConfig struct {
	// OriginsFilter is a regular expression that acts as a filter against the
	// `Origin` header value for pre-flight checks.
	OriginsFilter *regexp.Regexp

	// AllowHeaders is the response string used to fill the
	// `Access-Control-Allow-Headers` header in pre-flight check responses. When
	// empty, the `Access-Control-Allow-Headers` header will not be sent to
	// clients during pre-flight checks.
	AllowHeaders string

	// AllowMethods is a list of HTTP method names which are allowed for this
	// handler.
	AllowMethods []string

	// AllowOrigin is the response string used to fill the
	// `Access-Control-Allow-Origin` header in pre-flight check
	// responses. When empty, defaults to "*".
	AllowOrigin string

	// CacheControl is the response string used to fill the `Cache-Control`
	// header in pre-flight check responses. When empty, the `Cache-Control`
	// header will not be sent to clients during pre-flight checks.
	CacheControl string
}

// CORSHandler returns a handler that responds to OPTIONS request so that CORS
// requests from an origin that matches the specified allowed origins regular
// expression are permitted, while other origins are denied. If a request origin
// matches the specified regular expression, the handler responds with the
// specified allowOriginResponse value in the `Access-Control-Allow-Origin` HTTP
// response header.
func CORSHandler(next http.Handler, config CORSConfig) http.Handler {
	// By definition a CORS handler will respond to the OPTIONS method, so
	// include that method if not already specified.
	config.AllowMethods = sortAndMaybeInsertString("OPTIONS", config.AllowMethods)
	allowedMethods := strings.Join(config.AllowMethods, ", ")
	allowedMethodsHandler := AllowedMethodsHandler(next, config.AllowMethods)

	var allowOrigin string
	if config.AllowOrigin == "" {
		allowOrigin = "*"
	} else {
		allowOrigin = config.AllowOrigin
	}

	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// When Cross Origin Resource Sharing (CORS) request arrives, the
		// browser submits an `Origin` header that specifies where the request
		// came from. This handler will deny requests that do not match the
		// specified regular expression.
		if origin := r.Header.Get("Origin"); origin != "" && !config.OriginsFilter.MatchString(origin) {
			Error(w, fmt.Sprintf("origin domain not permitted: %q", origin), http.StatusForbidden)
			return
		}

		// All responses, not just pre-flight checks, require
		// `Access-Control-Allow-Origin` header to handle so-called "simple
		// requests," which do not require a pre-flight check by the browser,
		// yet the browser still inspects the response's headers for this value.
		w.Header().Set("Access-Control-Allow-Origin", allowOrigin)

		if r.Method == "OPTIONS" {
			// If the request method is OPTIONS, this may be a pre-flight
			// check. Respond as normally would for an OPTIONS request, but
			// include headers that notify the browser that the pre-flight is
			// successful.
			if config.CacheControl != "" {
				w.Header().Set("Cache-Control", config.CacheControl)
			}
			if config.AllowHeaders != "" {
				w.Header().Set("Access-Control-Allow-Headers", config.AllowHeaders)
			}
			w.Header().Set("Access-Control-Allow-Methods", allowedMethods)

			// During pre-flight checks, browser also submits the following
			// header to specify what method it would like to use.
			requestMethod := r.Header.Get("Access-Control-Request-Method")
			i := sort.SearchStrings(config.AllowMethods, requestMethod)
			if i == len(config.AllowMethods) || config.AllowMethods[i] != requestMethod {
				// Requested method is not on the list of allowed methods.
				Error(w, requestMethod, http.StatusMethodNotAllowed)
				return
			}

			// Nothing further to do for this OPTIONS handler.
			return
		}

		allowedMethodsHandler.ServeHTTP(w, r)
	})
}

func sortAndMaybeInsertString(s string, a []string) []string {
	if len(a) == 0 {
		return append(a, s)
	}

	sort.Strings(a)

	i := sort.SearchStrings(a, s)

	if i < len(a) && a[i] == s {
		return a // return slice when string already present
	}

	// Without two copies and mandatory allocation, insert string into array at
	// index.
	a = append(a, a[len(a)-1])
	copy(a[i+1:], a[i:len(a)-1])
	a[i] = s

	return a
}

// AllowedMethodsHandler returns a handler that only permits specified request
// methods, and responds with an error message when request method is not a
// member of the sorted list of allowed methods.
func AllowedMethodsHandler(next http.Handler, sortedAllowedMethods []string) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		i := sort.SearchStrings(sortedAllowedMethods, r.Method)
		if i == len(sortedAllowedMethods) || sortedAllowedMethods[i] != r.Method {
			Error(w, r.Method, http.StatusMethodNotAllowed)
			return
		}
		next.ServeHTTP(w, r)
	})
}
<commit_msg>change CORS' Cache-Control header to Access-Control-Max-Age<commit_after>package gohm

import (
	"fmt"
	"net/http"
	"regexp"
	"sort"
	"strconv"
	"strings"
)

// CORSConfig holds parameters for configuring a CORSHandler.
type CORSConfig struct {
	// OriginsFilter is a regular expression that acts as a filter against the
	// `Origin` header value for pre-flight checks.
	OriginsFilter *regexp.Regexp

	// AllowHeaders is the value for the `Access-Control-Allow-Headers` header
	// in pre-flight check responses. When empty, the
	// `Access-Control-Allow-Headers` header will not be sent to clients during
	// pre-flight checks.
	AllowHeaders string

	// AllowMethods is a list of HTTP method names which are allowed for this
	// handler.
	AllowMethods []string

	// AllowOrigin is the value for the `Access-Control-Allow-Origin` header in
	// pre-flight check responses. When empty, defaults to "*".
	AllowOrigin string

	// MaxAgeSeconds is the number of seconds used to fill the
	// `Access-Control-Max-Age` header in pre-flight check responses.
	MaxAgeSeconds int
}

// CORSHandler returns a handler that responds to OPTIONS request so that CORS
// requests from an origin that matches the specified allowed origins regular
// expression are permitted, while other origins are denied. If a request origin
// matches the specified regular expression, the handler responds with the
// specified allowOriginResponse value in the `Access-Control-Allow-Origin` HTTP
// response header.
func CORSHandler(next http.Handler, config CORSConfig) http.Handler {
	// By definition a CORS handler will respond to the OPTIONS method, so
	// include that method if not already specified.
	config.AllowMethods = sortAndMaybeInsertString("OPTIONS", config.AllowMethods)
	allowedMethods := strings.Join(config.AllowMethods, ", ")
	allowedMethodsHandler := AllowedMethodsHandler(next, config.AllowMethods)

	var allowOrigin string
	if config.AllowOrigin == "" {
		allowOrigin = "*"
	} else {
		allowOrigin = config.AllowOrigin
	}

	maxAge := strconv.Itoa(config.MaxAgeSeconds)

	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// When Cross Origin Resource Sharing (CORS) request arrives, the
		// browser submits an `Origin` header that specifies where the request
		// came from. This handler will deny requests that do not match the
		// specified regular expression.
		if origin := r.Header.Get("Origin"); origin != "" && !config.OriginsFilter.MatchString(origin) {
			Error(w, fmt.Sprintf("origin domain not permitted: %q", origin), http.StatusForbidden)
			return
		}

		// All responses, not just pre-flight checks, require
		// `Access-Control-Allow-Origin` header to handle so-called "simple
		// requests," which do not require a pre-flight check by the browser,
		// yet the browser still inspects the response's headers for this value.
		w.Header().Set("Access-Control-Allow-Origin", allowOrigin)

		if r.Method == "OPTIONS" {
			// If the request method is OPTIONS, this may be a pre-flight
			// check. Respond as normally would for an OPTIONS request, but
			// include headers that notify the browser that the pre-flight is
			// successful.
			if config.AllowHeaders != "" {
				w.Header().Set("Access-Control-Allow-Headers", config.AllowHeaders)
			}
			w.Header().Set("Access-Control-Allow-Methods", allowedMethods)
			w.Header().Set("Access-Control-Max-Age", maxAge)

			// During pre-flight checks, browser also submits the following
			// header to specify what method it would like to use.
			requestMethod := r.Header.Get("Access-Control-Request-Method")
			i := sort.SearchStrings(config.AllowMethods, requestMethod)
			if i == len(config.AllowMethods) || config.AllowMethods[i] != requestMethod {
				// Requested method is not on the list of allowed methods.
				Error(w, requestMethod, http.StatusMethodNotAllowed)
				return
			}

			// Nothing further to do for this OPTIONS handler.
			return
		}

		allowedMethodsHandler.ServeHTTP(w, r)
	})
}

func sortAndMaybeInsertString(s string, a []string) []string {
	if len(a) == 0 {
		return append(a, s)
	}

	sort.Strings(a)

	i := sort.SearchStrings(a, s)

	if i < len(a) && a[i] == s {
		return a // return slice when string already present
	}

	// Without two copies and mandatory allocation, insert string into array at
	// index.
	a = append(a, a[len(a)-1])
	copy(a[i+1:], a[i:len(a)-1])
	a[i] = s

	return a
}

// AllowedMethodsHandler returns a handler that only permits specified request
// methods, and responds with an error message when request method is not a
// member of the sorted list of allowed methods.
func AllowedMethodsHandler(next http.Handler, sortedAllowedMethods []string) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		i := sort.SearchStrings(sortedAllowedMethods, r.Method)
		if i == len(sortedAllowedMethods) || sortedAllowedMethods[i] != r.Method {
			Error(w, r.Method, http.StatusMethodNotAllowed)
			return
		}
		next.ServeHTTP(w, r)
	})
}
<|endoftext|>