<commit_before>package supervisor

import (
	"fmt"
	"testing"
	"time"

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

type simpleservice int

func (s *simpleservice) String() string {
	return fmt.Sprintf("simple service %d", int(*s))
}

func (s *simpleservice) Serve(ctx context.Context) {
	var i int
	for {
		i++
		fmt.Println("service started:", *s, "iteration:", i)
		select {
		case <-ctx.Done():
			fmt.Println("context done:", ctx.Err(), *s)
			return
		default:
			time.Sleep(500 * time.Millisecond)
		}
	}
}

func ExampleSupervisor() {
	var supervisor Supervisor

	svc := simpleservice(1)
	supervisor.Add(&svc)

	ctx, _ := context.WithTimeout(context.Background(), 1*time.Second)
	supervisor.Serve(ctx)
}

func TestString(t *testing.T) {
	const expected = "test"
	var supervisor Supervisor
	supervisor.Name = expected

	if got := fmt.Sprintf("%s", &supervisor); got != expected {
		t.Errorf("error getting supervisor name: %s", got)
	}
}

func TestSimple(t *testing.T) {
	var supervisor Supervisor

	svc := simpleservice(1)
	supervisor.Add(&svc)

	ctx, _ := context.WithTimeout(context.Background(), 1*time.Second)
	supervisor.Serve(ctx)

	countService(t, &supervisor)
}

func TestMultiple(t *testing.T) {
	var supervisor Supervisor

	svc1 := simpleservice(2)
	supervisor.Add(&svc1)
	svc2 := simpleservice(3)
	supervisor.Add(&svc2)

	ctx, _ := context.WithTimeout(context.Background(), 1*time.Second)
	supervisor.Serve(ctx)

	countService(t, &supervisor)
}

func TestCascaded(t *testing.T) {
	var supervisor Supervisor

	svc1 := simpleservice(4)
	supervisor.Add(&svc1)
	svc2 := simpleservice(5)
	supervisor.Add(&svc2)

	var childSupervisor Supervisor
	svc3 := simpleservice(6)
	childSupervisor.Add(&svc3)
	svc4 := simpleservice(7)
	childSupervisor.Add(&svc4)

	supervisor.Add(&childSupervisor)

	ctx, _ := context.WithTimeout(context.Background(), 1*time.Second)
	supervisor.Serve(ctx)

	countService(t, &supervisor)
}

type panicservice int

func (s *panicservice) Serve(ctx context.Context) {
	for {
		fmt.Println("panic service started:", *s)
		select {
		case <-ctx.Done():
			fmt.Println("panic service context:", ctx.Err(), *s)
			return
		default:
			time.Sleep(100 * time.Millisecond)
			panic("forcing panic")
		}
	}
}

func TestPanic(t *testing.T) {
	var supervisor Supervisor

	svc1 := panicservice(1)
	supervisor.Add(&svc1)

	ctx, _ := context.WithTimeout(context.Background(), 1*time.Second)
	supervisor.Serve(ctx)

	countService(t, &supervisor)
}

type failingservice int

func (s *failingservice) Serve(ctx context.Context) {
	for {
		fmt.Println("failing service started:", *s, "times")
		select {
		case <-ctx.Done():
			fmt.Println("failing service context:", ctx.Err(), *s, "times")
			return
		default:
			time.Sleep(100 * time.Millisecond)
			*s++
			return
		}
	}
}

func (s *failingservice) String() string {
	return fmt.Sprintf("failing service %v", *s)
}

func TestFailing(t *testing.T) {
	supervisor := Supervisor{
		Backoff: 1 * time.Second,
		Log: func(msg string) {
			t.Log("supervisor log:", msg)
		},
	}

	svc1 := failingservice(1)
	supervisor.Add(&svc1)

	ctx, _ := context.WithTimeout(context.Background(), 3*time.Second)
	supervisor.Serve(ctx)

	countService(t, &supervisor)
}

func TestAddServiceAfterServe(t *testing.T) {
	var supervisor Supervisor

	svc1 := simpleservice(1)
	supervisor.Add(&svc1)

	ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
	done := make(chan struct{})
	go func() {
		supervisor.Serve(ctx)
		done <- struct{}{}
	}()

	<-supervisor.startedServices
	svc2 := simpleservice(2)
	supervisor.Add(&svc2)
	<-supervisor.startedServices

	cancel()
	<-ctx.Done()
	<-done

	countService(t, &supervisor)
}

func TestRemoveServiceAfterServe(t *testing.T) {
	var supervisor Supervisor

	svc1 := simpleservice(1)
	supervisor.Add(&svc1)
	svc2 := simpleservice(2)
	supervisor.Add(&svc2)

	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	done := make(chan struct{})

	go func() {
		supervisor.Serve(ctx)
		done <- struct{}{}
	}()

	lbefore := getServiceCount(&supervisor)
	supervisor.Remove("unknown service")
	lafter := getServiceCount(&supervisor)

	if lbefore != lafter {
		t.Error("the removal of an unknown service shouldn't happen")
	}

	<-supervisor.startedServices
	supervisor.Remove(svc1.String())
	fmt.Println("removed service")

	lremoved := getServiceCount(&supervisor)
	if lbefore != lremoved {
		t.Error("the removal of a service should have affected the supervisor:", lbefore, lremoved)
	}

	cancel()
	<-ctx.Done()
	<-done

	countService(t, &supervisor)
}

func countService(t *testing.T, supervisor *Supervisor) {
	if l := len(supervisor.services); l != 0 {
		t.Errorf("not all services were stopped. possibly a bug: %d services left", l)
	}
}

func getServiceCount(s *Supervisor) int {
	s.servicesMu.Lock()
	l := len(s.services)
	s.servicesMu.Unlock()
	return l
}

func TestServices(t *testing.T) {
	var supervisor Supervisor

	svc1 := simpleservice(1)
	supervisor.Add(&svc1)
	svc2 := simpleservice(2)
	supervisor.Add(&svc2)

	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	done := make(chan struct{})

	go func() {
		supervisor.Serve(ctx)
		done <- struct{}{}
	}()

	<-supervisor.startedServices
	svcs := supervisor.Services()
	fmt.Println(svcs)
	for _, svcname := range []string{svc1.String(), svc2.String()} {
		if _, ok := svcs[svcname]; !ok {
			t.Errorf("expected service not found: %s", svcname)
		}
	}

	cancel()
	<-ctx.Done()
	<-done

}
<commit_msg>test: improve panic service output<commit_after>package supervisor

import (
	"fmt"
	"testing"
	"time"

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

type simpleservice int

func (s *simpleservice) String() string {
	return fmt.Sprintf("simple service %d", int(*s))
}

func (s *simpleservice) Serve(ctx context.Context) {
	var i int
	for {
		i++
		fmt.Println("service started:", *s, "iteration:", i)
		select {
		case <-ctx.Done():
			fmt.Println("context done:", ctx.Err(), *s)
			return
		default:
			time.Sleep(500 * time.Millisecond)
		}
	}
}

func ExampleSupervisor() {
	var supervisor Supervisor

	svc := simpleservice(1)
	supervisor.Add(&svc)

	ctx, _ := context.WithTimeout(context.Background(), 1*time.Second)
	supervisor.Serve(ctx)
}

func TestString(t *testing.T) {
	const expected = "test"
	var supervisor Supervisor
	supervisor.Name = expected

	if got := fmt.Sprintf("%s", &supervisor); got != expected {
		t.Errorf("error getting supervisor name: %s", got)
	}
}

func TestSimple(t *testing.T) {
	var supervisor Supervisor

	svc := simpleservice(1)
	supervisor.Add(&svc)

	ctx, _ := context.WithTimeout(context.Background(), 1*time.Second)
	supervisor.Serve(ctx)

	countService(t, &supervisor)
}

func TestMultiple(t *testing.T) {
	var supervisor Supervisor

	svc1 := simpleservice(2)
	supervisor.Add(&svc1)
	svc2 := simpleservice(3)
	supervisor.Add(&svc2)

	ctx, _ := context.WithTimeout(context.Background(), 1*time.Second)
	supervisor.Serve(ctx)

	countService(t, &supervisor)
}

func TestCascaded(t *testing.T) {
	var supervisor Supervisor

	svc1 := simpleservice(4)
	supervisor.Add(&svc1)
	svc2 := simpleservice(5)
	supervisor.Add(&svc2)

	var childSupervisor Supervisor
	svc3 := simpleservice(6)
	childSupervisor.Add(&svc3)
	svc4 := simpleservice(7)
	childSupervisor.Add(&svc4)

	supervisor.Add(&childSupervisor)

	ctx, _ := context.WithTimeout(context.Background(), 1*time.Second)
	supervisor.Serve(ctx)

	countService(t, &supervisor)
}

type panicservice int

func (s *panicservice) Serve(ctx context.Context) {
	for {
		fmt.Println("panic service started:", *s)
		select {
		case <-ctx.Done():
			fmt.Println("panic service context:", ctx.Err(), *s)
			return
		default:
			time.Sleep(100 * time.Millisecond)
			panic("forcing panic")
		}
	}
}

func (s *panicservice) String() string {
	return fmt.Sprintf("panic service %v", *s)
}

func TestPanic(t *testing.T) {
	var supervisor Supervisor

	svc1 := panicservice(1)
	supervisor.Add(&svc1)

	ctx, _ := context.WithTimeout(context.Background(), 1*time.Second)
	supervisor.Serve(ctx)

	countService(t, &supervisor)
}

type failingservice int

func (s *failingservice) Serve(ctx context.Context) {
	for {
		fmt.Println("failing service started:", *s, "times")
		select {
		case <-ctx.Done():
			fmt.Println("failing service context:", ctx.Err(), *s, "times")
			return
		default:
			time.Sleep(100 * time.Millisecond)
			*s++
			return
		}
	}
}

func (s *failingservice) String() string {
	return fmt.Sprintf("failing service %v", *s)
}

func TestFailing(t *testing.T) {
	supervisor := Supervisor{
		Backoff: 1 * time.Second,
		Log: func(msg string) {
			t.Log("supervisor log:", msg)
		},
	}

	svc1 := failingservice(1)
	supervisor.Add(&svc1)

	ctx, _ := context.WithTimeout(context.Background(), 3*time.Second)
	supervisor.Serve(ctx)

	countService(t, &supervisor)
}

func TestAddServiceAfterServe(t *testing.T) {
	var supervisor Supervisor

	svc1 := simpleservice(1)
	supervisor.Add(&svc1)

	ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
	done := make(chan struct{})
	go func() {
		supervisor.Serve(ctx)
		done <- struct{}{}
	}()

	<-supervisor.startedServices
	svc2 := simpleservice(2)
	supervisor.Add(&svc2)
	<-supervisor.startedServices

	cancel()
	<-ctx.Done()
	<-done

	countService(t, &supervisor)
}

func TestRemoveServiceAfterServe(t *testing.T) {
	var supervisor Supervisor

	svc1 := simpleservice(1)
	supervisor.Add(&svc1)
	svc2 := simpleservice(2)
	supervisor.Add(&svc2)

	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	done := make(chan struct{})

	go func() {
		supervisor.Serve(ctx)
		done <- struct{}{}
	}()

	lbefore := getServiceCount(&supervisor)
	supervisor.Remove("unknown service")
	lafter := getServiceCount(&supervisor)

	if lbefore != lafter {
		t.Error("the removal of an unknown service shouldn't happen")
	}

	<-supervisor.startedServices
	supervisor.Remove(svc1.String())
	fmt.Println("removed service")

	lremoved := getServiceCount(&supervisor)
	if lbefore != lremoved {
		t.Error("the removal of a service should have affected the supervisor:", lbefore, lremoved)
	}

	cancel()
	<-ctx.Done()
	<-done

	countService(t, &supervisor)
}

func countService(t *testing.T, supervisor *Supervisor) {
	if l := len(supervisor.services); l != 0 {
		t.Errorf("not all services were stopped. possibly a bug: %d services left", l)
	}
}

func getServiceCount(s *Supervisor) int {
	s.servicesMu.Lock()
	l := len(s.services)
	s.servicesMu.Unlock()
	return l
}

func TestServices(t *testing.T) {
	var supervisor Supervisor

	svc1 := simpleservice(1)
	supervisor.Add(&svc1)
	svc2 := simpleservice(2)
	supervisor.Add(&svc2)

	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	done := make(chan struct{})

	go func() {
		supervisor.Serve(ctx)
		done <- struct{}{}
	}()

	<-supervisor.startedServices
	svcs := supervisor.Services()
	fmt.Println(svcs)
	for _, svcname := range []string{svc1.String(), svc2.String()} {
		if _, ok := svcs[svcname]; !ok {
			t.Errorf("expected service not found: %s", svcname)
		}
	}

	cancel()
	<-ctx.Done()
	<-done

}
<|endoftext|>


<commit_before>package dns

import (
	"github.com/GoogleCloudPlatform/kubernetes/pkg/client"

	"github.com/coreos/go-etcd/etcd"
	"github.com/prometheus/client_golang/prometheus"
	backendetcd "github.com/skynetservices/skydns/backends/etcd"
	"github.com/skynetservices/skydns/server"
)

// NewServerDefaults returns the default SkyDNS server configuration for a DNS server.
func NewServerDefaults() (*server.Config, error) {
	config := &server.Config{
		Domain: "cluster.local.",
		Local:  "openshift.default.svc.cluster.local.",
	}
	return config, server.SetDefaults(config)
}

// ListenAndServe starts a DNS server that exposes services and values stored in etcd (if etcdclient
// is not nil). It will block until the server exits.
// TODO: hoist the service accessor out of this package so it can be reused.
func ListenAndServe(config *server.Config, client *client.Client, etcdclient *etcd.Client) error {
	stop := make(chan struct{})
	accessor := NewCachedServiceAccessor(client, stop)
	resolver := NewServiceResolver(config, accessor, client, openshiftFallback)
	resolvers := server.FirstBackend{resolver}
	if etcdclient != nil {
		resolvers = append(resolvers, backendetcd.NewBackend(etcdclient, &backendetcd.Config{
			Ttl:      config.Ttl,
			Priority: config.Priority,
		}))
	}

	s := server.New(resolvers, config)
	defer close(stop)
	return s.Run()
}

func openshiftFallback(name string, exact bool) (string, bool) {
	if name == "openshift.default.svc" {
		return "kubernetes.default.svc.", true
	}
	if name == "_endpoints.openshift.default.svc" {
		return "_endpoints.kubernetes.default.", true
	}
	return "", false
}

// counter is a SkyDNS compatible Counter
type counter struct {
	prometheus.Counter
}

// newCounter registers a prometheus counter and wraps it to match SkyDNS
func newCounter(c prometheus.Counter) server.Counter {
	prometheus.MustRegister(c)
	return counter{c}
}

// Inc increases the counter with the given value
func (c counter) Inc(val int64) {
	c.Counter.Add(float64(val))
}

// Add prometheus logging to SkyDNS
func init() {
	server.StatsForwardCount = newCounter(prometheus.NewCounter(prometheus.CounterOpts{
		Name: "dns_forward_count",
		Help: "Counter of DNS requests forwarded",
	}))
	server.StatsLookupCount = newCounter(prometheus.NewCounter(prometheus.CounterOpts{
		Name: "dns_lookup_count",
		Help: "Counter of DNS lookups performed",
	}))
	server.StatsRequestCount = newCounter(prometheus.NewCounter(prometheus.CounterOpts{
		Name: "dns_request_count",
		Help: "Counter of DNS requests made",
	}))
	server.StatsDnssecOkCount = newCounter(prometheus.NewCounter(prometheus.CounterOpts{
		Name: "dns_dnssec_ok_count",
		Help: "Counter of DNSSEC requests that were valid",
	}))
	server.StatsDnssecCacheMiss = newCounter(prometheus.NewCounter(prometheus.CounterOpts{
		Name: "dns_dnssec_cache_miss_count",
		Help: "Counter of DNSSEC requests that missed the cache",
	}))
	server.StatsNameErrorCount = newCounter(prometheus.NewCounter(prometheus.CounterOpts{
		Name: "dns_name_error_count",
		Help: "Counter of DNS requests resulting in a name error",
	}))
	server.StatsNoDataCount = newCounter(prometheus.NewCounter(prometheus.CounterOpts{
		Name: "dns_no_data_count",
		Help: "Counter of DNS requests that contained no data",
	}))
}
<commit_msg>prevent skydns metrics panic<commit_after>package dns

import (
	"github.com/GoogleCloudPlatform/kubernetes/pkg/client"

	"github.com/coreos/go-etcd/etcd"
	"github.com/prometheus/client_golang/prometheus"
	backendetcd "github.com/skynetservices/skydns/backends/etcd"
	"github.com/skynetservices/skydns/server"
)

// NewServerDefaults returns the default SkyDNS server configuration for a DNS server.
func NewServerDefaults() (*server.Config, error) {
	config := &server.Config{
		Domain: "cluster.local.",
		Local:  "openshift.default.svc.cluster.local.",
	}
	return config, server.SetDefaults(config)
}

// ListenAndServe starts a DNS server that exposes services and values stored in etcd (if etcdclient
// is not nil). It will block until the server exits.
// TODO: hoist the service accessor out of this package so it can be reused.
func ListenAndServe(config *server.Config, client *client.Client, etcdclient *etcd.Client) error {
	stop := make(chan struct{})
	accessor := NewCachedServiceAccessor(client, stop)
	resolver := NewServiceResolver(config, accessor, client, openshiftFallback)
	resolvers := server.FirstBackend{resolver}
	if etcdclient != nil {
		resolvers = append(resolvers, backendetcd.NewBackend(etcdclient, &backendetcd.Config{
			Ttl:      config.Ttl,
			Priority: config.Priority,
		}))
	}

	server.Metrics()
	s := server.New(resolvers, config)
	defer close(stop)
	return s.Run()
}

func openshiftFallback(name string, exact bool) (string, bool) {
	if name == "openshift.default.svc" {
		return "kubernetes.default.svc.", true
	}
	if name == "_endpoints.openshift.default.svc" {
		return "_endpoints.kubernetes.default.", true
	}
	return "", false
}

// counter is a SkyDNS compatible Counter
type counter struct {
	prometheus.Counter
}

// newCounter registers a prometheus counter and wraps it to match SkyDNS
func newCounter(c prometheus.Counter) server.Counter {
	prometheus.MustRegister(c)
	return counter{c}
}

// Inc increases the counter with the given value
func (c counter) Inc(val int64) {
	c.Counter.Add(float64(val))
}

// Add prometheus logging to SkyDNS
func init() {
	server.StatsForwardCount = newCounter(prometheus.NewCounter(prometheus.CounterOpts{
		Name: "dns_forward_count",
		Help: "Counter of DNS requests forwarded",
	}))
	server.StatsLookupCount = newCounter(prometheus.NewCounter(prometheus.CounterOpts{
		Name: "dns_lookup_count",
		Help: "Counter of DNS lookups performed",
	}))
	server.StatsRequestCount = newCounter(prometheus.NewCounter(prometheus.CounterOpts{
		Name: "dns_request_count",
		Help: "Counter of DNS requests made",
	}))
	server.StatsDnssecOkCount = newCounter(prometheus.NewCounter(prometheus.CounterOpts{
		Name: "dns_dnssec_ok_count",
		Help: "Counter of DNSSEC requests that were valid",
	}))
	server.StatsDnssecCacheMiss = newCounter(prometheus.NewCounter(prometheus.CounterOpts{
		Name: "dns_dnssec_cache_miss_count",
		Help: "Counter of DNSSEC requests that missed the cache",
	}))
	server.StatsNameErrorCount = newCounter(prometheus.NewCounter(prometheus.CounterOpts{
		Name: "dns_name_error_count",
		Help: "Counter of DNS requests resulting in a name error",
	}))
	server.StatsNoDataCount = newCounter(prometheus.NewCounter(prometheus.CounterOpts{
		Name: "dns_no_data_count",
		Help: "Counter of DNS requests that contained no data",
	}))
}
<|endoftext|>


<commit_before>package surveys

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

	"github.com/AreaHQ/jsonhal"
	"github.com/ONSdigital/go-launch-a-survey/settings"
)

// LauncherSchema is a representation of a schema in the Launcher
type LauncherSchema struct {
	Name     string
	EqID     string
	FormType string
	URL      string
}

// LauncherSchemas is a separation of Test and Live schemas
type LauncherSchemas struct {
	Business []LauncherSchema
	Census   []LauncherSchema
	Social   []LauncherSchema
	Test     []LauncherSchema
	Other    []LauncherSchema
}

// RegisterResponse is the response from the eq-survey-register request
type RegisterResponse struct {
	jsonhal.Hal
}

// Schemas is a list of Schema
type Schemas []Schema

// Schema is an available schema
type Schema struct {
	jsonhal.Hal
	Name string `json:"name"`
}

var eqIDFormTypeRegex = regexp.MustCompile(`^(?P<eq_id>[a-z0-9]+)_(?P<form_type>\w+)`)

func extractEqIDFormType(schema string) (EqID, formType string) {
	match := eqIDFormTypeRegex.FindStringSubmatch(schema)
	if match != nil {
		EqID = match[1]
		formType = match[2]
	}
	return
}

// LauncherSchemaFromFilename creates a LauncherSchema record from a schema filename
func LauncherSchemaFromFilename(filename string) LauncherSchema {
	EqID, formType := extractEqIDFormType(filename)
	return LauncherSchema{
		Name:     filename,
		EqID:     EqID,
		FormType: formType,
	}
}

// GetAvailableSchemas Gets the list of static schemas an joins them with any schemas from the eq-survey-register if defined
func GetAvailableSchemas() LauncherSchemas {
	schemaList := LauncherSchemas{
		Business: []LauncherSchema{
			LauncherSchemaFromFilename("1_0005.json"),
			LauncherSchemaFromFilename("1_0102.json"),
			LauncherSchemaFromFilename("1_0112.json"),
			LauncherSchemaFromFilename("1_0203.json"),
			LauncherSchemaFromFilename("1_0205.json"),
			LauncherSchemaFromFilename("1_0213.json"),
			LauncherSchemaFromFilename("1_0215.json"),
			LauncherSchemaFromFilename("2_0001.json"),
			LauncherSchemaFromFilename("e_commerce.json"),
			LauncherSchemaFromFilename("mbs_0106.json"),
			LauncherSchemaFromFilename("mbs_0111.json"),
			LauncherSchemaFromFilename("mbs_0117.json"),
			LauncherSchemaFromFilename("mbs_0123.json"),
			LauncherSchemaFromFilename("mbs_0158.json"),
			LauncherSchemaFromFilename("mbs_0161.json"),
			LauncherSchemaFromFilename("mbs_0167.json"),
			LauncherSchemaFromFilename("mbs_0173.json"),
			LauncherSchemaFromFilename("mbs_0201.json"),
			LauncherSchemaFromFilename("mbs_0202.json"),
			LauncherSchemaFromFilename("mbs_0203.json"),
			LauncherSchemaFromFilename("mbs_0204.json"),
			LauncherSchemaFromFilename("mbs_0205.json"),
			LauncherSchemaFromFilename("mbs_0216.json"),
			LauncherSchemaFromFilename("mbs_0251.json"),
			LauncherSchemaFromFilename("mbs_0253.json"),
			LauncherSchemaFromFilename("mbs_0255.json"),
			LauncherSchemaFromFilename("mbs_0817.json"),
			LauncherSchemaFromFilename("mbs_0823.json"),
			LauncherSchemaFromFilename("mbs_0867.json"),
			LauncherSchemaFromFilename("mbs_0873.json"),
			LauncherSchemaFromFilename("mci_transformation.json"),
			LauncherSchemaFromFilename("rsi_transformation.json"),
		},
		Census: []LauncherSchema{
			LauncherSchemaFromFilename("census_communal.json"),
			LauncherSchemaFromFilename("census_household.json"),
			LauncherSchemaFromFilename("census_individual.json"),
		},
		Social: []LauncherSchema{
			LauncherSchemaFromFilename("lms_1.json"),
		},
		Test: []LauncherSchema{
			LauncherSchemaFromFilename("0_star_wars.json"),
			LauncherSchemaFromFilename("multiple_answers.json"),
			LauncherSchemaFromFilename("test_big_list_naughty_strings.json"),
			LauncherSchemaFromFilename("test_checkbox.json"),
			LauncherSchemaFromFilename("test_checkbox_mutually_exclusive.json"),
			LauncherSchemaFromFilename("test_conditional_dates.json"),
			LauncherSchemaFromFilename("test_conditional_routing.json"),
			LauncherSchemaFromFilename("test_confirmation_question.json"),
			LauncherSchemaFromFilename("test_currency.json"),
			LauncherSchemaFromFilename("test_date_validation_combined.json"),
			LauncherSchemaFromFilename("test_date_validation_mm_yyyy_combined.json"),
			LauncherSchemaFromFilename("test_date_validation_yyyy_combined.json"),
			LauncherSchemaFromFilename("test_date_validation_range.json"),
			LauncherSchemaFromFilename("test_date_validation_single.json"),
			LauncherSchemaFromFilename("test_dates.json"),
			LauncherSchemaFromFilename("test_default.json"),
			LauncherSchemaFromFilename("test_dependencies_calculation.json"),
			LauncherSchemaFromFilename("test_dependencies_max_value.json"),
			LauncherSchemaFromFilename("test_dependencies_min_value.json"),
			LauncherSchemaFromFilename("test_difference_in_years.json"),
			LauncherSchemaFromFilename("test_difference_in_years_month_year.json"),
			LauncherSchemaFromFilename("test_difference_in_years_month_year_range.json"),
			LauncherSchemaFromFilename("test_difference_in_years_range.json"),
			LauncherSchemaFromFilename("test_dropdown_mandatory.json"),
			LauncherSchemaFromFilename("test_dropdown_mandatory_with_overridden_error.json"),
			LauncherSchemaFromFilename("test_dropdown_optional.json"),
			LauncherSchemaFromFilename("test_error_messages.json"),
			LauncherSchemaFromFilename("test_final_confirmation.json"),
			LauncherSchemaFromFilename("test_household_question.json"),
			LauncherSchemaFromFilename("test_interstitial_page.json"),
			LauncherSchemaFromFilename("test_introduction.json"),
			LauncherSchemaFromFilename("test_language.json"),
			LauncherSchemaFromFilename("test_markup.json"),
			LauncherSchemaFromFilename("test_metadata_routing.json"),
			LauncherSchemaFromFilename("test_multiple_piping.json"),
			LauncherSchemaFromFilename("test_navigation.json"),
			LauncherSchemaFromFilename("test_navigation_completeness.json"),
			LauncherSchemaFromFilename("test_navigation_confirmation.json"),
			LauncherSchemaFromFilename("test_navigation_routing.json"),
			LauncherSchemaFromFilename("test_numbers.json"),
			LauncherSchemaFromFilename("test_percentage.json"),
			LauncherSchemaFromFilename("test_question_definition.json"),
			LauncherSchemaFromFilename("test_question_guidance.json"),
			LauncherSchemaFromFilename("test_radio_checkbox_descriptions.json"),
			LauncherSchemaFromFilename("test_radio_mandatory.json"),
			LauncherSchemaFromFilename("test_radio_mandatory_with_mandatory_other.json"),
			LauncherSchemaFromFilename("test_radio_mandatory_with_mandatory_other_overridden_error.json"),
			LauncherSchemaFromFilename("test_radio_mandatory_with_optional_other.json"),
			LauncherSchemaFromFilename("test_radio_mandatory_with_overridden_error.json"),
			LauncherSchemaFromFilename("test_radio_optional.json"),
			LauncherSchemaFromFilename("test_radio_optional_with_mandatory_other.json"),
			LauncherSchemaFromFilename("test_radio_optional_with_mandatory_other_overridden_error.json"),
			LauncherSchemaFromFilename("test_radio_optional_with_optional_other.json"),
			LauncherSchemaFromFilename("test_relationship_household.json"),
			LauncherSchemaFromFilename("test_repeating_and_conditional_routing.json"),
			LauncherSchemaFromFilename("test_repeating_household.json"),
			LauncherSchemaFromFilename("test_repeating_household_routing.json"),
			LauncherSchemaFromFilename("test_routing_date_equals.json"),
			LauncherSchemaFromFilename("test_routing_date_greater_than.json"),
			LauncherSchemaFromFilename("test_routing_date_less_than.json"),
			LauncherSchemaFromFilename("test_routing_date_not_equals.json"),
			LauncherSchemaFromFilename("test_routing_group.json"),
			LauncherSchemaFromFilename("test_routing_number_equals.json"),
			LauncherSchemaFromFilename("test_routing_number_greater_than.json"),
			LauncherSchemaFromFilename("test_routing_number_greater_than_or_equal.json"),
			LauncherSchemaFromFilename("test_routing_number_less_than.json"),
			LauncherSchemaFromFilename("test_routing_number_less_than_or_equal.json"),
			LauncherSchemaFromFilename("test_routing_number_not_equals.json"),
			LauncherSchemaFromFilename("test_routing_on_multiple_select.json"),
			LauncherSchemaFromFilename("test_skip_condition.json"),
			LauncherSchemaFromFilename("test_skip_condition_block.json"),
			LauncherSchemaFromFilename("test_skip_condition_group.json"),
			LauncherSchemaFromFilename("test_skip_condition_not_set.json"),
			LauncherSchemaFromFilename("test_skip_condition_set.json"),
			LauncherSchemaFromFilename("test_summary.json"),
			LauncherSchemaFromFilename("test_section_summary.json"),
			LauncherSchemaFromFilename("test_sum_equal_validation_against_total.json"),
			LauncherSchemaFromFilename("test_sum_equal_or_less_validation_against_total.json"),
			LauncherSchemaFromFilename("test_sum_less_validation_against_total.json"),
			LauncherSchemaFromFilename("test_sum_multi_validation_against_total.json"),
			LauncherSchemaFromFilename("test_titles.json"),
			LauncherSchemaFromFilename("test_titles_conditional_within_repeating_block.json"),
			LauncherSchemaFromFilename("test_titles_radio_and_checkbox.json"),
			LauncherSchemaFromFilename("test_titles_within_repeating_blocks.json"),
            LauncherSchemaFromFilename("test_titles_repeating_non_repeating_dependency.json"),
			LauncherSchemaFromFilename("test_view_submitted_response.json"),
			LauncherSchemaFromFilename("test_textarea.json"),
			LauncherSchemaFromFilename("test_textfield.json"),
			LauncherSchemaFromFilename("test_timeout.json"),
			LauncherSchemaFromFilename("test_total_breakdown.json"),
			LauncherSchemaFromFilename("test_unit_patterns.json"),
		},
	}

	schemaList.Other = getAvailableSchemasFromRegister()

	return schemaList
}

func getAvailableSchemasFromRegister() []LauncherSchema {

	schemaList := []LauncherSchema{}

	if settings.Get("SURVEY_REGISTER_URL") != "" {
		req, err := http.NewRequest("GET", settings.Get("SURVEY_REGISTER_URL"), nil)
		if err != nil {
			log.Fatal("NewRequest: ", err)
			return []LauncherSchema{}
		}
		client := &http.Client{}

		resp, err := client.Do(req)
		if err != nil {
			log.Fatal("Do: ", err)
			return []LauncherSchema{}
		}

		defer resp.Body.Close()

		var registerResponse RegisterResponse

		if err := json.NewDecoder(resp.Body).Decode(&registerResponse); err != nil {
			log.Println(err)
		}

		var schemas Schemas

		schemasJSON, _ := json.Marshal(registerResponse.Embedded["schemas"])

		if err := json.Unmarshal(schemasJSON, &schemas); err != nil {
			log.Println(err)
		}

		for _, schema := range schemas {
			url := schema.Links["self"]
			EqID, formType := extractEqIDFormType(schema.Name)
			schemaList = append(schemaList, LauncherSchema{
				Name:     schema.Name,
				URL:      url.Href,
				EqID:     EqID,
				FormType: formType,
			})
		}
	}

	return schemaList
}

// FindSurveyByName Finds the schema in the list of available schemas
func FindSurveyByName(name string) LauncherSchema {
	for _, survey := range GetAvailableSchemas().Business {
		if survey.Name == name {
			return survey
		}
	}
	for _, survey := range GetAvailableSchemas().Census {
		if survey.Name == name {
			return survey
		}
	}
	for _, survey := range GetAvailableSchemas().Social {
		if survey.Name == name {
			return survey
		}
	}
	for _, survey := range GetAvailableSchemas().Test {
		if survey.Name == name {
			return survey
		}
	}
	for _, survey := range GetAvailableSchemas().Other {
		if survey.Name == name {
			return survey
		}
	}
	panic("Survey not found")
}
<commit_msg>Add test_durations.json<commit_after>package surveys

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

	"github.com/AreaHQ/jsonhal"
	"github.com/ONSdigital/go-launch-a-survey/settings"
)

// LauncherSchema is a representation of a schema in the Launcher
type LauncherSchema struct {
	Name     string
	EqID     string
	FormType string
	URL      string
}

// LauncherSchemas is a separation of Test and Live schemas
type LauncherSchemas struct {
	Business []LauncherSchema
	Census   []LauncherSchema
	Social   []LauncherSchema
	Test     []LauncherSchema
	Other    []LauncherSchema
}

// RegisterResponse is the response from the eq-survey-register request
type RegisterResponse struct {
	jsonhal.Hal
}

// Schemas is a list of Schema
type Schemas []Schema

// Schema is an available schema
type Schema struct {
	jsonhal.Hal
	Name string `json:"name"`
}

var eqIDFormTypeRegex = regexp.MustCompile(`^(?P<eq_id>[a-z0-9]+)_(?P<form_type>\w+)`)

func extractEqIDFormType(schema string) (EqID, formType string) {
	match := eqIDFormTypeRegex.FindStringSubmatch(schema)
	if match != nil {
		EqID = match[1]
		formType = match[2]
	}
	return
}

// LauncherSchemaFromFilename creates a LauncherSchema record from a schema filename
func LauncherSchemaFromFilename(filename string) LauncherSchema {
	EqID, formType := extractEqIDFormType(filename)
	return LauncherSchema{
		Name:     filename,
		EqID:     EqID,
		FormType: formType,
	}
}

// GetAvailableSchemas Gets the list of static schemas an joins them with any schemas from the eq-survey-register if defined
func GetAvailableSchemas() LauncherSchemas {
	schemaList := LauncherSchemas{
		Business: []LauncherSchema{
			LauncherSchemaFromFilename("1_0005.json"),
			LauncherSchemaFromFilename("1_0102.json"),
			LauncherSchemaFromFilename("1_0112.json"),
			LauncherSchemaFromFilename("1_0203.json"),
			LauncherSchemaFromFilename("1_0205.json"),
			LauncherSchemaFromFilename("1_0213.json"),
			LauncherSchemaFromFilename("1_0215.json"),
			LauncherSchemaFromFilename("2_0001.json"),
			LauncherSchemaFromFilename("e_commerce.json"),
			LauncherSchemaFromFilename("mbs_0106.json"),
			LauncherSchemaFromFilename("mbs_0111.json"),
			LauncherSchemaFromFilename("mbs_0117.json"),
			LauncherSchemaFromFilename("mbs_0123.json"),
			LauncherSchemaFromFilename("mbs_0158.json"),
			LauncherSchemaFromFilename("mbs_0161.json"),
			LauncherSchemaFromFilename("mbs_0167.json"),
			LauncherSchemaFromFilename("mbs_0173.json"),
			LauncherSchemaFromFilename("mbs_0201.json"),
			LauncherSchemaFromFilename("mbs_0202.json"),
			LauncherSchemaFromFilename("mbs_0203.json"),
			LauncherSchemaFromFilename("mbs_0204.json"),
			LauncherSchemaFromFilename("mbs_0205.json"),
			LauncherSchemaFromFilename("mbs_0216.json"),
			LauncherSchemaFromFilename("mbs_0251.json"),
			LauncherSchemaFromFilename("mbs_0253.json"),
			LauncherSchemaFromFilename("mbs_0255.json"),
			LauncherSchemaFromFilename("mbs_0817.json"),
			LauncherSchemaFromFilename("mbs_0823.json"),
			LauncherSchemaFromFilename("mbs_0867.json"),
			LauncherSchemaFromFilename("mbs_0873.json"),
			LauncherSchemaFromFilename("mci_transformation.json"),
			LauncherSchemaFromFilename("rsi_transformation.json"),
		},
		Census: []LauncherSchema{
			LauncherSchemaFromFilename("census_communal.json"),
			LauncherSchemaFromFilename("census_household.json"),
			LauncherSchemaFromFilename("census_individual.json"),
		},
		Social: []LauncherSchema{
			LauncherSchemaFromFilename("lms_1.json"),
		},
		Test: []LauncherSchema{
			LauncherSchemaFromFilename("0_star_wars.json"),
			LauncherSchemaFromFilename("multiple_answers.json"),
			LauncherSchemaFromFilename("test_big_list_naughty_strings.json"),
			LauncherSchemaFromFilename("test_checkbox.json"),
			LauncherSchemaFromFilename("test_checkbox_mutually_exclusive.json"),
			LauncherSchemaFromFilename("test_conditional_dates.json"),
			LauncherSchemaFromFilename("test_conditional_routing.json"),
			LauncherSchemaFromFilename("test_confirmation_question.json"),
			LauncherSchemaFromFilename("test_currency.json"),
			LauncherSchemaFromFilename("test_date_validation_combined.json"),
			LauncherSchemaFromFilename("test_date_validation_mm_yyyy_combined.json"),
			LauncherSchemaFromFilename("test_date_validation_yyyy_combined.json"),
			LauncherSchemaFromFilename("test_date_validation_range.json"),
			LauncherSchemaFromFilename("test_date_validation_single.json"),
			LauncherSchemaFromFilename("test_dates.json"),
			LauncherSchemaFromFilename("test_default.json"),
			LauncherSchemaFromFilename("test_dependencies_calculation.json"),
			LauncherSchemaFromFilename("test_dependencies_max_value.json"),
			LauncherSchemaFromFilename("test_dependencies_min_value.json"),
			LauncherSchemaFromFilename("test_difference_in_years.json"),
			LauncherSchemaFromFilename("test_difference_in_years_month_year.json"),
			LauncherSchemaFromFilename("test_difference_in_years_month_year_range.json"),
			LauncherSchemaFromFilename("test_difference_in_years_range.json"),
			LauncherSchemaFromFilename("test_dropdown_mandatory.json"),
			LauncherSchemaFromFilename("test_dropdown_mandatory_with_overridden_error.json"),
			LauncherSchemaFromFilename("test_dropdown_optional.json"),
			LauncherSchemaFromFilename("test_durations.json"),
			LauncherSchemaFromFilename("test_error_messages.json"),
			LauncherSchemaFromFilename("test_final_confirmation.json"),
			LauncherSchemaFromFilename("test_household_question.json"),
			LauncherSchemaFromFilename("test_interstitial_page.json"),
			LauncherSchemaFromFilename("test_introduction.json"),
			LauncherSchemaFromFilename("test_language.json"),
			LauncherSchemaFromFilename("test_markup.json"),
			LauncherSchemaFromFilename("test_metadata_routing.json"),
			LauncherSchemaFromFilename("test_multiple_piping.json"),
			LauncherSchemaFromFilename("test_navigation.json"),
			LauncherSchemaFromFilename("test_navigation_completeness.json"),
			LauncherSchemaFromFilename("test_navigation_confirmation.json"),
			LauncherSchemaFromFilename("test_navigation_routing.json"),
			LauncherSchemaFromFilename("test_numbers.json"),
			LauncherSchemaFromFilename("test_percentage.json"),
			LauncherSchemaFromFilename("test_question_definition.json"),
			LauncherSchemaFromFilename("test_question_guidance.json"),
			LauncherSchemaFromFilename("test_radio_checkbox_descriptions.json"),
			LauncherSchemaFromFilename("test_radio_mandatory.json"),
			LauncherSchemaFromFilename("test_radio_mandatory_with_mandatory_other.json"),
			LauncherSchemaFromFilename("test_radio_mandatory_with_mandatory_other_overridden_error.json"),
			LauncherSchemaFromFilename("test_radio_mandatory_with_optional_other.json"),
			LauncherSchemaFromFilename("test_radio_mandatory_with_overridden_error.json"),
			LauncherSchemaFromFilename("test_radio_optional.json"),
			LauncherSchemaFromFilename("test_radio_optional_with_mandatory_other.json"),
			LauncherSchemaFromFilename("test_radio_optional_with_mandatory_other_overridden_error.json"),
			LauncherSchemaFromFilename("test_radio_optional_with_optional_other.json"),
			LauncherSchemaFromFilename("test_relationship_household.json"),
			LauncherSchemaFromFilename("test_repeating_and_conditional_routing.json"),
			LauncherSchemaFromFilename("test_repeating_household.json"),
			LauncherSchemaFromFilename("test_repeating_household_routing.json"),
			LauncherSchemaFromFilename("test_routing_date_equals.json"),
			LauncherSchemaFromFilename("test_routing_date_greater_than.json"),
			LauncherSchemaFromFilename("test_routing_date_less_than.json"),
			LauncherSchemaFromFilename("test_routing_date_not_equals.json"),
			LauncherSchemaFromFilename("test_routing_group.json"),
			LauncherSchemaFromFilename("test_routing_number_equals.json"),
			LauncherSchemaFromFilename("test_routing_number_greater_than.json"),
			LauncherSchemaFromFilename("test_routing_number_greater_than_or_equal.json"),
			LauncherSchemaFromFilename("test_routing_number_less_than.json"),
			LauncherSchemaFromFilename("test_routing_number_less_than_or_equal.json"),
			LauncherSchemaFromFilename("test_routing_number_not_equals.json"),
			LauncherSchemaFromFilename("test_routing_on_multiple_select.json"),
			LauncherSchemaFromFilename("test_skip_condition.json"),
			LauncherSchemaFromFilename("test_skip_condition_block.json"),
			LauncherSchemaFromFilename("test_skip_condition_group.json"),
			LauncherSchemaFromFilename("test_skip_condition_not_set.json"),
			LauncherSchemaFromFilename("test_skip_condition_set.json"),
			LauncherSchemaFromFilename("test_summary.json"),
			LauncherSchemaFromFilename("test_section_summary.json"),
			LauncherSchemaFromFilename("test_sum_equal_validation_against_total.json"),
			LauncherSchemaFromFilename("test_sum_equal_or_less_validation_against_total.json"),
			LauncherSchemaFromFilename("test_sum_less_validation_against_total.json"),
			LauncherSchemaFromFilename("test_sum_multi_validation_against_total.json"),
			LauncherSchemaFromFilename("test_titles.json"),
			LauncherSchemaFromFilename("test_titles_conditional_within_repeating_block.json"),
			LauncherSchemaFromFilename("test_titles_radio_and_checkbox.json"),
			LauncherSchemaFromFilename("test_titles_within_repeating_blocks.json"),
            LauncherSchemaFromFilename("test_titles_repeating_non_repeating_dependency.json"),
			LauncherSchemaFromFilename("test_view_submitted_response.json"),
			LauncherSchemaFromFilename("test_textarea.json"),
			LauncherSchemaFromFilename("test_textfield.json"),
			LauncherSchemaFromFilename("test_timeout.json"),
			LauncherSchemaFromFilename("test_total_breakdown.json"),
			LauncherSchemaFromFilename("test_unit_patterns.json"),
		},
	}

	schemaList.Other = getAvailableSchemasFromRegister()

	return schemaList
}

func getAvailableSchemasFromRegister() []LauncherSchema {

	schemaList := []LauncherSchema{}

	if settings.Get("SURVEY_REGISTER_URL") != "" {
		req, err := http.NewRequest("GET", settings.Get("SURVEY_REGISTER_URL"), nil)
		if err != nil {
			log.Fatal("NewRequest: ", err)
			return []LauncherSchema{}
		}
		client := &http.Client{}

		resp, err := client.Do(req)
		if err != nil {
			log.Fatal("Do: ", err)
			return []LauncherSchema{}
		}

		defer resp.Body.Close()

		var registerResponse RegisterResponse

		if err := json.NewDecoder(resp.Body).Decode(&registerResponse); err != nil {
			log.Println(err)
		}

		var schemas Schemas

		schemasJSON, _ := json.Marshal(registerResponse.Embedded["schemas"])

		if err := json.Unmarshal(schemasJSON, &schemas); err != nil {
			log.Println(err)
		}

		for _, schema := range schemas {
			url := schema.Links["self"]
			EqID, formType := extractEqIDFormType(schema.Name)
			schemaList = append(schemaList, LauncherSchema{
				Name:     schema.Name,
				URL:      url.Href,
				EqID:     EqID,
				FormType: formType,
			})
		}
	}

	return schemaList
}

// FindSurveyByName Finds the schema in the list of available schemas
func FindSurveyByName(name string) LauncherSchema {
	for _, survey := range GetAvailableSchemas().Business {
		if survey.Name == name {
			return survey
		}
	}
	for _, survey := range GetAvailableSchemas().Census {
		if survey.Name == name {
			return survey
		}
	}
	for _, survey := range GetAvailableSchemas().Social {
		if survey.Name == name {
			return survey
		}
	}
	for _, survey := range GetAvailableSchemas().Test {
		if survey.Name == name {
			return survey
		}
	}
	for _, survey := range GetAvailableSchemas().Other {
		if survey.Name == name {
			return survey
		}
	}
	panic("Survey not found")
}
<|endoftext|>


<commit_before>package jwtmiddleware

import (
	"context"
	"errors"
	"fmt"
	"github.com/dgrijalva/jwt-go"
	"log"
	"net/http"
	"strings"
)

// A function called whenever an error is encountered
type errorHandler func(w http.ResponseWriter, r *http.Request, err string)

// TokenExtractor is a function that takes a request as input and returns
// either a token or an error.  An error should only be returned if an attempt
// to specify a token was found, but the information was somehow incorrectly
// formed.  In the case where a token is simply not present, this should not
// be treated as an error.  An empty string should be returned in that case.
type TokenExtractor func(r *http.Request) (string, error)

// Options is a struct for specifying configuration options for the middleware.
type Options struct {
	// The function that will return the Key to validate the JWT.
	// It can be either a shared secret or a public key.
	// Default value: nil
	ValidationKeyGetter jwt.Keyfunc
	// The name of the property in the request where the user information
	// from the JWT will be stored.
	// Default value: "user"
	UserProperty string
	// The function that will be called when there's an error validating the token
	// Default value:
	ErrorHandler errorHandler
	// A boolean indicating if the credentials are required or not
	// Default value: false
	CredentialsOptional bool
	// A function that extracts the token from the request
	// Default: FromAuthHeader (i.e., from Authorization header as bearer token)
	Extractor TokenExtractor
	// Debug flag turns on debugging output
	// Default: false
	Debug bool
	// When set, all requests with the OPTIONS method will use authentication
	// Default: false
	EnableAuthOnOptions bool
	// When set, the middelware verifies that tokens are signed with the specific signing algorithm
	// If the signing method is not constant the ValidationKeyGetter callback can be used to implement additional checks
	// Important to avoid security issues described here: https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/
	// Default: nil
	SigningMethod jwt.SigningMethod
}

type JWTMiddleware struct {
	Options Options
}

func OnError(w http.ResponseWriter, r *http.Request, err string) {
	http.Error(w, err, http.StatusUnauthorized)
}

// New constructs a new Secure instance with supplied options.
func New(options ...Options) *JWTMiddleware {

	var opts Options
	if len(options) == 0 {
		opts = Options{}
	} else {
		opts = options[0]
	}

	if opts.UserProperty == "" {
		opts.UserProperty = "user"
	}

	if opts.ErrorHandler == nil {
		opts.ErrorHandler = OnError
	}

	if opts.Extractor == nil {
		opts.Extractor = FromAuthHeader
	}

	return &JWTMiddleware{
		Options: opts,
	}
}

func (m *JWTMiddleware) logf(format string, args ...interface{}) {
	if m.Options.Debug {
		log.Printf(format, args...)
	}
}

// Special implementation for Negroni, but could be used elsewhere.
func (m *JWTMiddleware) HandlerWithNext(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
	err := m.CheckJWT(w, r)

	// If there was an error, do not call next.
	if err == nil && next != nil {
		next(w, r)
	}
}

func (m *JWTMiddleware) Handler(h http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// Let secure process the request. If it returns an error,
		// that indicates the request should not continue.
		err := m.CheckJWT(w, r)

		// If there was an error, do not continue.
		if err != nil {
			return
		}

		h.ServeHTTP(w, r)
	})
}

// FromAuthHeader is a "TokenExtractor" that takes a give request and extracts
// the JWT token from the Authorization header.
func FromAuthHeader(r *http.Request) (string, error) {
	authHeader := r.Header.Get("Authorization")
	if authHeader == "" {
		return "", nil // No error, just no token
	}

	// TODO: Make this a bit more robust, parsing-wise
	authHeaderParts := strings.Split(authHeader, " ")
	if len(authHeaderParts) != 2 || strings.ToLower(authHeaderParts[0]) != "bearer" {
		return "", errors.New("Authorization header format must be Bearer {token}")
	}

	return authHeaderParts[1], nil
}

// FromParameter returns a function that extracts the token from the specified
// query string parameter
func FromParameter(param string) TokenExtractor {
	return func(r *http.Request) (string, error) {
		return r.URL.Query().Get(param), nil
	}
}

// FromFirst returns a function that runs multiple token extractors and takes the
// first token it finds
func FromFirst(extractors ...TokenExtractor) TokenExtractor {
	return func(r *http.Request) (string, error) {
		for _, ex := range extractors {
			token, err := ex(r)
			if err != nil {
				return "", err
			}
			if token != "" {
				return token, nil
			}
		}
		return "", nil
	}
}

func (m *JWTMiddleware) CheckJWT(w http.ResponseWriter, r *http.Request) error {
	if !m.Options.EnableAuthOnOptions {
		if r.Method == "OPTIONS" {
			return nil
		}
	}

	// Use the specified token extractor to extract a token from the request
	token, err := m.Options.Extractor(r)

	// If debugging is turned on, log the outcome
	if err != nil {
		m.logf("Error extracting JWT: %v", err)
	} else {
		m.logf("Token extracted: %s", token)
	}

	// If an error occurs, call the error handler and return an error
	if err != nil {
		m.Options.ErrorHandler(w, r, err.Error())
		return fmt.Errorf("Error extracting token: %v", err)
	}

	// If the token is empty...
	if token == "" {
		// Check if it was required
		if m.Options.CredentialsOptional {
			m.logf("  No credentials found (CredentialsOptional=true)")
			// No error, just no token (and that is ok given that CredentialsOptional is true)
			return nil
		}

		// If we get here, the required token is missing
		errorMsg := "Required authorization token not found"
		m.Options.ErrorHandler(w, r, errorMsg)
		m.logf("  Error: No credentials found (CredentialsOptional=false)")
		return fmt.Errorf(errorMsg)
	}

	// Now parse the token
	parsedToken, err := jwt.Parse(token, m.Options.ValidationKeyGetter)

	// Check if there was an error in parsing...
	if err != nil {
		m.logf("Error parsing token: %v", err)
		m.Options.ErrorHandler(w, r, err.Error())
		return fmt.Errorf("Error parsing token: %v", err)
	}

	if m.Options.SigningMethod != nil && m.Options.SigningMethod.Alg() != parsedToken.Header["alg"] {
		message := fmt.Sprintf("Expected %s signing method but token specified %s",
			m.Options.SigningMethod.Alg(),
			parsedToken.Header["alg"])
		m.logf("Error validating token algorithm: %s", message)
		m.Options.ErrorHandler(w, r, errors.New(message).Error())
		return fmt.Errorf("Error validating token algorithm: %s", message)
	}

	// Check if the parsed token is valid...
	if !parsedToken.Valid {
		m.logf("Token is invalid")
		m.Options.ErrorHandler(w, r, "The token isn't valid")
		return errors.New("Token is invalid")
	}

	m.logf("JWT: %v", parsedToken)

	// If we get here, everything worked and we can set the
	// user property in context.
	newRequest := r.WithContext(context.WithValue(r.Context(), m.Options.UserProperty, parsedToken))
	// Update the current request with the new context information.
	*r = *newRequest
	return nil
}
<commit_msg>remove unneccessary variable<commit_after>package jwtmiddleware

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

	"github.com/dgrijalva/jwt-go"
)

// A function called whenever an error is encountered
type errorHandler func(w http.ResponseWriter, r *http.Request, err string)

// TokenExtractor is a function that takes a request as input and returns
// either a token or an error.  An error should only be returned if an attempt
// to specify a token was found, but the information was somehow incorrectly
// formed.  In the case where a token is simply not present, this should not
// be treated as an error.  An empty string should be returned in that case.
type TokenExtractor func(r *http.Request) (string, error)

// Options is a struct for specifying configuration options for the middleware.
type Options struct {
	// The function that will return the Key to validate the JWT.
	// It can be either a shared secret or a public key.
	// Default value: nil
	ValidationKeyGetter jwt.Keyfunc
	// The name of the property in the request where the user information
	// from the JWT will be stored.
	// Default value: "user"
	UserProperty string
	// The function that will be called when there's an error validating the token
	// Default value:
	ErrorHandler errorHandler
	// A boolean indicating if the credentials are required or not
	// Default value: false
	CredentialsOptional bool
	// A function that extracts the token from the request
	// Default: FromAuthHeader (i.e., from Authorization header as bearer token)
	Extractor TokenExtractor
	// Debug flag turns on debugging output
	// Default: false
	Debug bool
	// When set, all requests with the OPTIONS method will use authentication
	// Default: false
	EnableAuthOnOptions bool
	// When set, the middelware verifies that tokens are signed with the specific signing algorithm
	// If the signing method is not constant the ValidationKeyGetter callback can be used to implement additional checks
	// Important to avoid security issues described here: https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/
	// Default: nil
	SigningMethod jwt.SigningMethod
}

type JWTMiddleware struct {
	Options Options
}

func OnError(w http.ResponseWriter, r *http.Request, err string) {
	http.Error(w, err, http.StatusUnauthorized)
}

// New constructs a new Secure instance with supplied options.
func New(options ...Options) *JWTMiddleware {

	var opts Options
	if len(options) == 0 {
		opts = Options{}
	} else {
		opts = options[0]
	}

	if opts.UserProperty == "" {
		opts.UserProperty = "user"
	}

	if opts.ErrorHandler == nil {
		opts.ErrorHandler = OnError
	}

	if opts.Extractor == nil {
		opts.Extractor = FromAuthHeader
	}

	return &JWTMiddleware{
		Options: opts,
	}
}

func (m *JWTMiddleware) logf(format string, args ...interface{}) {
	if m.Options.Debug {
		log.Printf(format, args...)
	}
}

// Special implementation for Negroni, but could be used elsewhere.
func (m *JWTMiddleware) HandlerWithNext(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
	err := m.CheckJWT(w, r)

	// If there was an error, do not call next.
	if err == nil && next != nil {
		next(w, r)
	}
}

func (m *JWTMiddleware) Handler(h http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// Let secure process the request. If it returns an error,
		// that indicates the request should not continue.
		err := m.CheckJWT(w, r)

		// If there was an error, do not continue.
		if err != nil {
			return
		}

		h.ServeHTTP(w, r)
	})
}

// FromAuthHeader is a "TokenExtractor" that takes a give request and extracts
// the JWT token from the Authorization header.
func FromAuthHeader(r *http.Request) (string, error) {
	authHeader := r.Header.Get("Authorization")
	if authHeader == "" {
		return "", nil // No error, just no token
	}

	// TODO: Make this a bit more robust, parsing-wise
	authHeaderParts := strings.Split(authHeader, " ")
	if len(authHeaderParts) != 2 || strings.ToLower(authHeaderParts[0]) != "bearer" {
		return "", errors.New("Authorization header format must be Bearer {token}")
	}

	return authHeaderParts[1], nil
}

// FromParameter returns a function that extracts the token from the specified
// query string parameter
func FromParameter(param string) TokenExtractor {
	return func(r *http.Request) (string, error) {
		return r.URL.Query().Get(param), nil
	}
}

// FromFirst returns a function that runs multiple token extractors and takes the
// first token it finds
func FromFirst(extractors ...TokenExtractor) TokenExtractor {
	return func(r *http.Request) (string, error) {
		for _, ex := range extractors {
			token, err := ex(r)
			if err != nil {
				return "", err
			}
			if token != "" {
				return token, nil
			}
		}
		return "", nil
	}
}

func (m *JWTMiddleware) CheckJWT(w http.ResponseWriter, r *http.Request) error {
	if !m.Options.EnableAuthOnOptions {
		if r.Method == "OPTIONS" {
			return nil
		}
	}

	// Use the specified token extractor to extract a token from the request
	token, err := m.Options.Extractor(r)

	// If debugging is turned on, log the outcome
	if err != nil {
		m.logf("Error extracting JWT: %v", err)
	} else {
		m.logf("Token extracted: %s", token)
	}

	// If an error occurs, call the error handler and return an error
	if err != nil {
		m.Options.ErrorHandler(w, r, err.Error())
		return fmt.Errorf("Error extracting token: %v", err)
	}

	// If the token is empty...
	if token == "" {
		// Check if it was required
		if m.Options.CredentialsOptional {
			m.logf("  No credentials found (CredentialsOptional=true)")
			// No error, just no token (and that is ok given that CredentialsOptional is true)
			return nil
		}

		// If we get here, the required token is missing
		errorMsg := "Required authorization token not found"
		m.Options.ErrorHandler(w, r, errorMsg)
		m.logf("  Error: No credentials found (CredentialsOptional=false)")
		return fmt.Errorf(errorMsg)
	}

	// Now parse the token
	parsedToken, err := jwt.Parse(token, m.Options.ValidationKeyGetter)

	// Check if there was an error in parsing...
	if err != nil {
		m.logf("Error parsing token: %v", err)
		m.Options.ErrorHandler(w, r, err.Error())
		return fmt.Errorf("Error parsing token: %v", err)
	}

	if m.Options.SigningMethod != nil && m.Options.SigningMethod.Alg() != parsedToken.Header["alg"] {
		message := fmt.Sprintf("Expected %s signing method but token specified %s",
			m.Options.SigningMethod.Alg(),
			parsedToken.Header["alg"])
		m.logf("Error validating token algorithm: %s", message)
		m.Options.ErrorHandler(w, r, errors.New(message).Error())
		return fmt.Errorf("Error validating token algorithm: %s", message)
	}

	// Check if the parsed token is valid...
	if !parsedToken.Valid {
		m.logf("Token is invalid")
		m.Options.ErrorHandler(w, r, "The token isn't valid")
		return errors.New("Token is invalid")
	}

	m.logf("JWT: %v", parsedToken)

	// If we get here, everything worked and we can set the
	// user property in context.
	*r = *r.WithContext(context.WithValue(r.Context(), m.Options.UserProperty, parsedToken))

	return nil
}
<|endoftext|>


<commit_before>package runrunc

import (
	"encoding/json"
	"io"
	"io/ioutil"
	"os/exec"
	"strings"

	"github.com/cloudfoundry-incubator/garden"
	"github.com/cloudfoundry-incubator/guardian/log"
	"github.com/cloudfoundry-incubator/guardian/rundmc/process_tracker"
	"github.com/cloudfoundry/gunk/command_runner"
	"github.com/opencontainers/specs"
	"github.com/pivotal-golang/lager"
)

const DefaultPath = "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"

var plog = log.Session("runrunc")

//go:generate counterfeiter . ProcessTracker
type ProcessTracker interface {
	Run(id uint32, cmd *exec.Cmd, io garden.ProcessIO, tty *garden.TTYSpec, signaller process_tracker.Signaller) (garden.Process, error)
}

//go:generate counterfeiter . PidGenerator
type PidGenerator interface {
	Generate() uint32
}

// da doo
type RunRunc struct {
	tracker       ProcessTracker
	commandRunner command_runner.CommandRunner
	pidGenerator  PidGenerator

	log log.ChainLogger
}

func New(tracker ProcessTracker, runner command_runner.CommandRunner, pidgen PidGenerator) *RunRunc {
	return &RunRunc{
		tracker:       tracker,
		commandRunner: runner,
		pidGenerator:  pidgen,

		log: plog,
	}
}

func (r RunRunc) WithLogSession(sess log.ChainLogger) *RunRunc {
	var cp RunRunc = r
	r.log = sess.Start("runrunc")
	r.commandRunner = &log.Runner{CommandRunner: r.commandRunner, Logger: r.log}

	return &cp
}

// Starts a bundle by running 'runc' in the bundle directory
func (r *RunRunc) Start(bundlePath string, io garden.ProcessIO) (garden.Process, error) {
	mlog := plog.Start("start", lager.Data{"bundle": bundlePath})
	defer mlog.Info("started")

	cmd := exec.Command("runc")
	cmd.Dir = bundlePath

	process, err := r.tracker.Run(r.pidGenerator.Generate(), cmd, io, nil, nil)
	return process, err
}

// Exec a process in a bundle using 'runc exec'
func (r *RunRunc) Exec(bundlePath string, spec garden.ProcessSpec, io garden.ProcessIO) (garden.Process, error) {
	mlog := plog.Start("exec", lager.Data{"bundle": bundlePath, "path": spec.Path})
	defer mlog.Info("execced")

	tmpFile, err := ioutil.TempFile("", "guardianprocess")
	if err != nil {
		return nil, mlog.Err("tempfile", err)
	}

	if err := writeProcessJSON(spec, tmpFile); err != nil {
		return nil, mlog.Err("encode", err)
	}

	cmd := exec.Command("runc", "exec", tmpFile.Name())
	cmd.Dir = bundlePath

	return r.tracker.Run(r.pidGenerator.Generate(), cmd, io, spec.TTY, nil)
}

// Kill a bundle using 'runc kill'
func (r *RunRunc) Kill(bundlePath string) error {
	mlog := plog.Start("kill", lager.Data{"bundle": bundlePath})
	defer mlog.Info("killed")

	cmd := exec.Command("runc", "kill")
	cmd.Dir = bundlePath
	return r.commandRunner.Run(cmd)
}

func writeProcessJSON(spec garden.ProcessSpec, writer io.Writer) error {
	return json.NewEncoder(writer).Encode(specs.Process{
		Args: append([]string{spec.Path}, spec.Args...),
		Env:  envWithPath(spec.Env),
	})
}

func envWithPath(env []string) []string {
	for _, envVar := range env {
		if strings.Contains(envVar, "PATH=") {
			return env
		}
	}

	return append(env, DefaultPath)
}
<commit_msg>Make runc start explicit.<commit_after>package runrunc

import (
	"encoding/json"
	"io"
	"io/ioutil"
	"os/exec"
	"strings"

	"github.com/cloudfoundry-incubator/garden"
	"github.com/cloudfoundry-incubator/guardian/log"
	"github.com/cloudfoundry-incubator/guardian/rundmc/process_tracker"
	"github.com/cloudfoundry/gunk/command_runner"
	"github.com/opencontainers/specs"
	"github.com/pivotal-golang/lager"
)

const DefaultPath = "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"

var plog = log.Session("runrunc")

//go:generate counterfeiter . ProcessTracker
type ProcessTracker interface {
	Run(id uint32, cmd *exec.Cmd, io garden.ProcessIO, tty *garden.TTYSpec, signaller process_tracker.Signaller) (garden.Process, error)
}

//go:generate counterfeiter . PidGenerator
type PidGenerator interface {
	Generate() uint32
}

// da doo
type RunRunc struct {
	tracker       ProcessTracker
	commandRunner command_runner.CommandRunner
	pidGenerator  PidGenerator

	log log.ChainLogger
}

func New(tracker ProcessTracker, runner command_runner.CommandRunner, pidgen PidGenerator) *RunRunc {
	return &RunRunc{
		tracker:       tracker,
		commandRunner: runner,
		pidGenerator:  pidgen,

		log: plog,
	}
}

func (r RunRunc) WithLogSession(sess log.ChainLogger) *RunRunc {
	var cp RunRunc = r
	r.log = sess.Start("runrunc")
	r.commandRunner = &log.Runner{CommandRunner: r.commandRunner, Logger: r.log}

	return &cp
}

// Starts a bundle by running 'runc' in the bundle directory
func (r *RunRunc) Start(bundlePath string, io garden.ProcessIO) (garden.Process, error) {
	mlog := plog.Start("start", lager.Data{"bundle": bundlePath})
	defer mlog.Info("started")

	cmd := exec.Command("runc", "start")
	cmd.Dir = bundlePath

	process, err := r.tracker.Run(r.pidGenerator.Generate(), cmd, io, nil, nil)
	return process, err
}

// Exec a process in a bundle using 'runc exec'
func (r *RunRunc) Exec(bundlePath string, spec garden.ProcessSpec, io garden.ProcessIO) (garden.Process, error) {
	mlog := plog.Start("exec", lager.Data{"bundle": bundlePath, "path": spec.Path})
	defer mlog.Info("execced")

	tmpFile, err := ioutil.TempFile("", "guardianprocess")
	if err != nil {
		return nil, mlog.Err("tempfile", err)
	}

	if err := writeProcessJSON(spec, tmpFile); err != nil {
		return nil, mlog.Err("encode", err)
	}

	cmd := exec.Command("runc", "exec", tmpFile.Name())
	cmd.Dir = bundlePath

	return r.tracker.Run(r.pidGenerator.Generate(), cmd, io, spec.TTY, nil)
}

// Kill a bundle using 'runc kill'
func (r *RunRunc) Kill(bundlePath string) error {
	mlog := plog.Start("kill", lager.Data{"bundle": bundlePath})
	defer mlog.Info("killed")

	cmd := exec.Command("runc", "kill")
	cmd.Dir = bundlePath
	return r.commandRunner.Run(cmd)
}

func writeProcessJSON(spec garden.ProcessSpec, writer io.Writer) error {
	return json.NewEncoder(writer).Encode(specs.Process{
		Args: append([]string{spec.Path}, spec.Args...),
		Env:  envWithPath(spec.Env),
	})
}

func envWithPath(env []string) []string {
	for _, envVar := range env {
		if strings.Contains(envVar, "PATH=") {
			return env
		}
	}

	return append(env, DefaultPath)
}
<|endoftext|>


<commit_before>package libkbfs

import (
	"golang.org/x/net/context"
	"reflect"
)

// CoalescingContext allows many contexts to be treated as one.  It waits on
// all its contexts' Context.Done() channels, and when all of them have
// returned, this CoalescingContext is canceled. At any point, a context can be
// added to the list, and will subsequently also be part of the wait condition.
type CoalescingContext struct {
	context.Context
	closeCh  chan struct{}
	doneCh   chan struct{}
	mutateCh chan context.Context
	selects  []reflect.SelectCase
}

func (ctx *CoalescingContext) loop() {
	for {
		chosen, val, _ := reflect.Select(ctx.selects)
		switch chosen {
		case 0:
			// request to mutate the select list
			newCase := val.Interface().(context.Context)
			if newCase != nil {
				ctx.addContextLocked(newCase)
			}
		case 1:
			// Done
			close(ctx.doneCh)
			return
		default:
			// The chosen channel has been closed. Remove it from our select list.
			ctx.selects = append(ctx.selects[:chosen], ctx.selects[chosen+1:]...)
			// If we have no more selects available, the request is done.
			if len(ctx.selects) == 2 {
				close(ctx.doneCh)
				return
			}
		}
	}
}

func (ctx *CoalescingContext) addContextLocked(other context.Context) {
	ctx.selects = append(ctx.selects, reflect.SelectCase{
		Dir:  reflect.SelectRecv,
		Chan: reflect.ValueOf(other.Done()),
	})
}

// NewCoalescingContext creates a new CoalescingContext. The context _must_ be
// canceled to avoid a goroutine leak.
func NewCoalescingContext(parent context.Context) (*CoalescingContext, context.CancelFunc) {
	ctx := &CoalescingContext{
		Context:  context.Background(),
		closeCh:  make(chan struct{}),
		doneCh:   make(chan struct{}),
		mutateCh: make(chan context.Context),
	}
	ctx.selects = []reflect.SelectCase{
		{
			Dir:  reflect.SelectRecv,
			Chan: reflect.ValueOf(ctx.mutateCh),
		},
		{
			Dir:  reflect.SelectRecv,
			Chan: reflect.ValueOf(ctx.closeCh),
		},
	}
	ctx.addContextLocked(parent)
	go ctx.loop()
	cancelFunc := func() {
		select {
		case <-ctx.closeCh:
		default:
			close(ctx.closeCh)
		}
	}
	return ctx, cancelFunc
}

// Done returns a channel that is closed when the CoalescingContext is
// canceled.
func (ctx *CoalescingContext) Done() <-chan struct{} {
	return ctx.doneCh
}

// Err returns context.Canceled if the CoalescingContext has been canceled, and
// nil otherwise.
func (ctx *CoalescingContext) Err() error {
	select {
	case <-ctx.doneCh:
		return context.Canceled
	default:
	}
	return nil
}

// AddContext adds a context to the set of contexts that we're waiting on.
func (ctx *CoalescingContext) AddContext(other context.Context) error {
	select {
	case ctx.mutateCh <- other:
		return nil
	case <-ctx.doneCh:
		return context.Canceled
	}
}
<commit_msg>Add TODO for timeout in coalescing context<commit_after>package libkbfs

import (
	"golang.org/x/net/context"
	"reflect"
)

// CoalescingContext allows many contexts to be treated as one.  It waits on
// all its contexts' Context.Done() channels, and when all of them have
// returned, this CoalescingContext is canceled. At any point, a context can be
// added to the list, and will subsequently also be part of the wait condition.
// TODO: add timeout channel in case there is a goroutine leak
type CoalescingContext struct {
	context.Context
	closeCh  chan struct{}
	doneCh   chan struct{}
	mutateCh chan context.Context
	selects  []reflect.SelectCase
}

func (ctx *CoalescingContext) loop() {
	for {
		chosen, val, _ := reflect.Select(ctx.selects)
		switch chosen {
		case 0:
			// request to mutate the select list
			newCase := val.Interface().(context.Context)
			if newCase != nil {
				ctx.addContextLocked(newCase)
			}
		case 1:
			// Done
			close(ctx.doneCh)
			return
		default:
			// The chosen channel has been closed. Remove it from our select list.
			ctx.selects = append(ctx.selects[:chosen], ctx.selects[chosen+1:]...)
			// If we have no more selects available, the request is done.
			if len(ctx.selects) == 2 {
				close(ctx.doneCh)
				return
			}
		}
	}
}

func (ctx *CoalescingContext) addContextLocked(other context.Context) {
	ctx.selects = append(ctx.selects, reflect.SelectCase{
		Dir:  reflect.SelectRecv,
		Chan: reflect.ValueOf(other.Done()),
	})
}

// NewCoalescingContext creates a new CoalescingContext. The context _must_ be
// canceled to avoid a goroutine leak.
func NewCoalescingContext(parent context.Context) (*CoalescingContext, context.CancelFunc) {
	ctx := &CoalescingContext{
		Context:  context.Background(),
		closeCh:  make(chan struct{}),
		doneCh:   make(chan struct{}),
		mutateCh: make(chan context.Context),
	}
	ctx.selects = []reflect.SelectCase{
		{
			Dir:  reflect.SelectRecv,
			Chan: reflect.ValueOf(ctx.mutateCh),
		},
		{
			Dir:  reflect.SelectRecv,
			Chan: reflect.ValueOf(ctx.closeCh),
		},
	}
	ctx.addContextLocked(parent)
	go ctx.loop()
	cancelFunc := func() {
		select {
		case <-ctx.closeCh:
		default:
			close(ctx.closeCh)
		}
	}
	return ctx, cancelFunc
}

// Done returns a channel that is closed when the CoalescingContext is
// canceled.
func (ctx *CoalescingContext) Done() <-chan struct{} {
	return ctx.doneCh
}

// Err returns context.Canceled if the CoalescingContext has been canceled, and
// nil otherwise.
func (ctx *CoalescingContext) Err() error {
	select {
	case <-ctx.doneCh:
		return context.Canceled
	default:
	}
	return nil
}

// AddContext adds a context to the set of contexts that we're waiting on.
func (ctx *CoalescingContext) AddContext(other context.Context) error {
	select {
	case ctx.mutateCh <- other:
		return nil
	case <-ctx.doneCh:
		return context.Canceled
	}
}
<|endoftext|>


<commit_before>package cocoa

// #include <stdlib.h>
//
// #include "input.h"
//
// @class EbitenGameWindow;
// @class NSOpenGLContext;
//
// typedef EbitenGameWindow* EbitenGameWindowPtr;
//
// EbitenGameWindow* CreateGameWindow(size_t width, size_t height, const char* title, NSOpenGLContext* glContext);
// NSOpenGLContext* CreateGLContext(NSOpenGLContext* sharedGLContext);
//
// void UseGLContext(NSOpenGLContext* glContext);
// void UnuseGLContext(void);
//
import "C"
import (
	"github.com/hajimehoshi/go-ebiten/graphics"
	"github.com/hajimehoshi/go-ebiten/graphics/opengl"
	"github.com/hajimehoshi/go-ebiten/ui"
	"runtime"
	"unsafe"
)

type GameWindow struct {
	screenWidth  int
	screenHeight int
	screenScale  int
	title        string
	native       *C.EbitenGameWindow
	pressedKeys  map[ui.Key]struct{}
	funcs        chan func(*opengl.Context)
	funcsDone    chan struct{}
	closed       chan struct{}
	events       chan interface{}
}

var windows = map[*C.EbitenGameWindow]*GameWindow{}

func newGameWindow(width, height, scale int, title string) *GameWindow {
	return &GameWindow{
		screenWidth:  width,
		screenHeight: height,
		screenScale:  scale,
		title:        title,
		pressedKeys:  map[ui.Key]struct{}{},
		funcs:        make(chan func(*opengl.Context)),
		funcsDone:    make(chan struct{}),
		closed:       make(chan struct{}),
	}
}

func (w *GameWindow) run(graphicsSharedContext *opengl.SharedContext, sharedGLContext *C.NSOpenGLContext) {
	cTitle := C.CString(w.title)
	defer C.free(unsafe.Pointer(cTitle))

	ch := make(chan struct{})
	go func() {
		runtime.LockOSThread()
		glContext := C.CreateGLContext(sharedGLContext)
		w.native = C.CreateGameWindow(C.size_t(w.screenWidth*w.screenScale),
			C.size_t(w.screenHeight*w.screenScale),
			cTitle,
			glContext)
		windows[w.native] = w
		close(ch)

		C.UseGLContext(glContext)
		context := graphicsSharedContext.CreateContext(
			w.screenWidth, w.screenHeight, w.screenScale)
		C.UnuseGLContext()

		w.loop(context, glContext)

		C.UseGLContext(glContext)
		context.Dispose()
		C.UnuseGLContext()
	}()
	<-ch
}

func (w *GameWindow) loop(context *opengl.Context, glContext *C.NSOpenGLContext) {
	for {
		select {
		case <-w.closed:
			return
		case f := <-w.funcs:
			C.UseGLContext(glContext)
			f(context)
			C.UnuseGLContext()
			w.funcsDone <- struct{}{}
		}
	}
}

func (w *GameWindow) Draw(f func(graphics.Context)) {
	w.useGLContext(func(context *opengl.Context) {
		context.Update(f)
	})
}

func (w *GameWindow) useGLContext(f func(*opengl.Context)) {
	w.funcs <- f
	<-w.funcsDone
}

func (w *GameWindow) Events() <-chan interface{} {
	if w.events != nil {
		return w.events
	}
	w.events = make(chan interface{})
	return w.events
}

func (w *GameWindow) notify(e interface{}) {
	if w.events == nil {
		return
	}
	go func() {
		w.events <- e
	}()
}

// Now this function is not used anywhere.
//export ebiten_WindowSizeUpdated
func ebiten_WindowSizeUpdated(nativeWindow C.EbitenGameWindowPtr, width, height int) {
	w := windows[nativeWindow]
	e := ui.WindowSizeUpdatedEvent{width, height}
	w.notify(e)
}

func (w *GameWindow) keyStateUpdatedEvent() ui.KeyStateUpdatedEvent {
	keys := []ui.Key{}
	for key, _ := range w.pressedKeys {
		keys = append(keys, key)
	}
	return ui.KeyStateUpdatedEvent{
		Keys: keys,
	}
}

var cocoaKeyCodeToKey = map[int]ui.Key{
	49:  ui.KeySpace,
	123: ui.KeyLeft,
	124: ui.KeyRight,
	125: ui.KeyDown,
	126: ui.KeyUp,
}

//export ebiten_KeyDown
func ebiten_KeyDown(nativeWindow C.EbitenGameWindowPtr, keyCode int) {
	key, ok := cocoaKeyCodeToKey[keyCode]
	if !ok {
		return
	}
	w := windows[nativeWindow]
	w.pressedKeys[key] = struct{}{}
	w.notify(w.keyStateUpdatedEvent())
}

//export ebiten_KeyUp
func ebiten_KeyUp(nativeWindow C.EbitenGameWindowPtr, keyCode int) {
	key, ok := cocoaKeyCodeToKey[keyCode]
	if !ok {
		return
	}
	w := windows[nativeWindow]
	delete(w.pressedKeys, key)
	w.notify(w.keyStateUpdatedEvent())
}

//export ebiten_MouseStateUpdated
func ebiten_MouseStateUpdated(nativeWindow C.EbitenGameWindowPtr, inputType C.InputType, cx, cy C.int) {
	w := windows[nativeWindow]

	if inputType == C.InputTypeMouseUp {
		e := ui.MouseStateUpdatedEvent{-1, -1}
		w.notify(e)
		return
	}

	x, y := int(cx), int(cy)
	x /= w.screenScale
	y /= w.screenScale
	if x < 0 {
		x = 0
	} else if w.screenWidth <= x {
		x = w.screenWidth - 1
	}
	if y < 0 {
		y = 0
	} else if w.screenHeight <= y {
		y = w.screenHeight - 1
	}
	e := ui.MouseStateUpdatedEvent{x, y}
	w.notify(e)
}

//export ebiten_WindowClosed
func ebiten_WindowClosed(nativeWindow C.EbitenGameWindowPtr) {
	w := windows[nativeWindow]
	close(w.closed)
	w.notify(ui.WindowClosedEvent{})
	delete(windows, nativeWindow)
}
<commit_msg>Bug fix: Ignore Draw when the window is closed<commit_after>package cocoa

// #include <stdlib.h>
//
// #include "input.h"
//
// @class EbitenGameWindow;
// @class NSOpenGLContext;
//
// typedef EbitenGameWindow* EbitenGameWindowPtr;
//
// EbitenGameWindow* CreateGameWindow(size_t width, size_t height, const char* title, NSOpenGLContext* glContext);
// NSOpenGLContext* CreateGLContext(NSOpenGLContext* sharedGLContext);
//
// void UseGLContext(NSOpenGLContext* glContext);
// void UnuseGLContext(void);
//
import "C"
import (
	"github.com/hajimehoshi/go-ebiten/graphics"
	"github.com/hajimehoshi/go-ebiten/graphics/opengl"
	"github.com/hajimehoshi/go-ebiten/ui"
	"runtime"
	"unsafe"
)

type GameWindow struct {
	screenWidth  int
	screenHeight int
	screenScale  int
	title        string
	native       *C.EbitenGameWindow
	pressedKeys  map[ui.Key]struct{}
	funcs        chan func(*opengl.Context)
	funcsDone    chan struct{}
	closed       chan struct{}
	events       chan interface{}
}

var windows = map[*C.EbitenGameWindow]*GameWindow{}

func newGameWindow(width, height, scale int, title string) *GameWindow {
	return &GameWindow{
		screenWidth:  width,
		screenHeight: height,
		screenScale:  scale,
		title:        title,
		pressedKeys:  map[ui.Key]struct{}{},
		funcs:        make(chan func(*opengl.Context)),
		funcsDone:    make(chan struct{}),
		closed:       make(chan struct{}),
	}
}

func (w *GameWindow) run(graphicsSharedContext *opengl.SharedContext, sharedGLContext *C.NSOpenGLContext) {
	cTitle := C.CString(w.title)
	defer C.free(unsafe.Pointer(cTitle))

	ch := make(chan struct{})
	go func() {
		runtime.LockOSThread()
		glContext := C.CreateGLContext(sharedGLContext)
		w.native = C.CreateGameWindow(C.size_t(w.screenWidth*w.screenScale),
			C.size_t(w.screenHeight*w.screenScale),
			cTitle,
			glContext)
		windows[w.native] = w
		close(ch)

		C.UseGLContext(glContext)
		context := graphicsSharedContext.CreateContext(
			w.screenWidth, w.screenHeight, w.screenScale)
		C.UnuseGLContext()

		defer func() {
			C.UseGLContext(glContext)
			context.Dispose()
			C.UnuseGLContext()
		}()

		w.loop(context, glContext)
	}()
	<-ch
}

func (w *GameWindow) loop(context *opengl.Context, glContext *C.NSOpenGLContext) {
	for {
		select {
		case <-w.closed:
			return
		case f := <-w.funcs:
			C.UseGLContext(glContext)
			f(context)
			C.UnuseGLContext()
			w.funcsDone <- struct{}{}
		}
	}
}

func (w *GameWindow) Draw(f func(graphics.Context)) {
	select {
	case <-w.closed:
		return
	default:
		w.useGLContext(func(context *opengl.Context) {
			context.Update(f)
		})
	}
}

func (w *GameWindow) useGLContext(f func(*opengl.Context)) {
	w.funcs <- f
	<-w.funcsDone
}

func (w *GameWindow) Events() <-chan interface{} {
	if w.events != nil {
		return w.events
	}
	w.events = make(chan interface{})
	return w.events
}

func (w *GameWindow) notify(e interface{}) {
	if w.events == nil {
		return
	}
	go func() {
		w.events <- e
	}()
}

// Now this function is not used anywhere.
//export ebiten_WindowSizeUpdated
func ebiten_WindowSizeUpdated(nativeWindow C.EbitenGameWindowPtr, width, height int) {
	w := windows[nativeWindow]
	e := ui.WindowSizeUpdatedEvent{width, height}
	w.notify(e)
}

func (w *GameWindow) keyStateUpdatedEvent() ui.KeyStateUpdatedEvent {
	keys := []ui.Key{}
	for key, _ := range w.pressedKeys {
		keys = append(keys, key)
	}
	return ui.KeyStateUpdatedEvent{
		Keys: keys,
	}
}

var cocoaKeyCodeToKey = map[int]ui.Key{
	49:  ui.KeySpace,
	123: ui.KeyLeft,
	124: ui.KeyRight,
	125: ui.KeyDown,
	126: ui.KeyUp,
}

//export ebiten_KeyDown
func ebiten_KeyDown(nativeWindow C.EbitenGameWindowPtr, keyCode int) {
	key, ok := cocoaKeyCodeToKey[keyCode]
	if !ok {
		return
	}
	w := windows[nativeWindow]
	w.pressedKeys[key] = struct{}{}
	w.notify(w.keyStateUpdatedEvent())
}

//export ebiten_KeyUp
func ebiten_KeyUp(nativeWindow C.EbitenGameWindowPtr, keyCode int) {
	key, ok := cocoaKeyCodeToKey[keyCode]
	if !ok {
		return
	}
	w := windows[nativeWindow]
	delete(w.pressedKeys, key)
	w.notify(w.keyStateUpdatedEvent())
}

//export ebiten_MouseStateUpdated
func ebiten_MouseStateUpdated(nativeWindow C.EbitenGameWindowPtr, inputType C.InputType, cx, cy C.int) {
	w := windows[nativeWindow]

	if inputType == C.InputTypeMouseUp {
		e := ui.MouseStateUpdatedEvent{-1, -1}
		w.notify(e)
		return
	}

	x, y := int(cx), int(cy)
	x /= w.screenScale
	y /= w.screenScale
	if x < 0 {
		x = 0
	} else if w.screenWidth <= x {
		x = w.screenWidth - 1
	}
	if y < 0 {
		y = 0
	} else if w.screenHeight <= y {
		y = w.screenHeight - 1
	}
	e := ui.MouseStateUpdatedEvent{x, y}
	w.notify(e)
}

//export ebiten_WindowClosed
func ebiten_WindowClosed(nativeWindow C.EbitenGameWindowPtr) {
	w := windows[nativeWindow]
	close(w.closed)
	w.notify(ui.WindowClosedEvent{})
	delete(windows, nativeWindow)
}
<|endoftext|>


<commit_before>package gohl72_test

import(
	"gohl72"
	"testing"
)

func TestBadHeader(t *testing.T){
	tests := []string{
		"M||",
		"||",
		"WRONG||",
		"",
	}

	for _, v := range tests{
		_, err := gohl72.NewParser([]byte(v))
		if err == nil{
			t.Fatalf("Expecting error with header %s\n",v)
		}
	}
}<commit_msg>fixing import path for bitbucket<commit_after>package gohl72_test

import(
	"testing"
	"bitbucket.org/yehezkel/gohl7"
)

func TestBadHeader(t *testing.T){
	tests := []string{
		"M||",
		"||",
		"WRONG||",
		"",
	}

	for _, v := range tests{
		_, err := gohl72.NewParser([]byte(v))
		if err == nil{
			t.Fatalf("Expecting error with header %s\n",v)
		}
	}
}
<|endoftext|>


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

// Parse URLs (actually URIs, but that seems overly pedantic).
// TODO(rsc): Add tests.

package http

import (
	"os";
	"strings"
)

// Errors introduced by ParseURL.
var (
	BadURL = os.NewError("bad url syntax")
)

func ishex(c byte) bool {
	switch {
	case '0' <= c && c <= '9':
		return true;
	case 'a' <= c && c <= 'f':
		return true;
	case 'A' <= c && c <= 'F':
		return true;
	}
	return false
}

func unhex(c byte) byte {
	switch {
	case '0' <= c && c <= '9':
		return c - '0';
	case 'a' <= c && c <= 'f':
		return c - 'a' + 10;
	case 'A' <= c && c <= 'F':
		return c - 'A' + 10;
	}
	return 0
}

// URLUnescape unescapes a URL-encoded string,
// converting %AB into the byte 0xAB.
// It returns a BadURL error if each % is not followed
// by two hexadecimal digits.
func URLUnescape(s string) (string, *os.Error) {
	// Count %, check that they're well-formed.
	n := 0;
	for i := 0; i < len(s); {
		if s[i] == '%' {
			n++;
			if !ishex(s[i+1]) || !ishex(s[i+2]) {
				return "", BadURL;
			}
			i += 3
		} else {
			i++
		}
	}

	if n == 0 {
		return s, nil
	}

	t := make([]byte, len(s)-2*n);
	j := 0;
	for i := 0; i < len(s); {
		if s[i] == '%' {
			t[j] = unhex(s[i+1]) << 4 | unhex(s[i+2]);
			j++;
			i += 3;
		} else {
			t[j] = s[i];
			j++;
			i++;
		}
	}
	return string(t), nil;
}

// A URL represents a parsed URL (technically, a URI reference).
// The general form represented is:
//	scheme://[userinfo@]host/path[?query][#fragment]
type URL struct {
	Raw string;		// the original string
	Scheme string;		// scheme
	RawPath string;		// //[userinfo@]host/path[?query][#fragment]
	Authority string;	// [userinfo@]host
	Userinfo string;	// userinfo
	Host string;		// host
	Path string;		// /path
	Query string;		// query
	Fragment string;	// fragment
}

// Maybe rawurl is of the form scheme:path.
// (Scheme must be [a-zA-Z][a-zA-Z0-9+-.]*)
// If so, return scheme, path; else return "", rawurl.
func getscheme(rawurl string) (scheme, path string, err *os.Error) {
	for i := 0; i < len(rawurl); i++ {
		c := rawurl[i];
		switch {
		case 'a' <= c && c <= 'z' ||'A' <= c && c <= 'Z':
			// do nothing
		case '0' <= c && c <= '9' || c == '+' || c == '-' || c == '.':
			if i == 0 {
				return "", rawurl, nil
			}
		case c == ':':
			if i == 0 {
				return "", "", BadURL
			}
			return rawurl[0:i], rawurl[i+1:len(rawurl)], nil
		}
	}
	return "", rawurl, nil
}

// Maybe s is of the form t c u.
// If so, return t, c u (or t, u if cutc == true).
// If not, return s, "".
func split(s string, c byte, cutc bool) (string, string) {
	for i := 0; i < len(s); i++ {
		if s[i] == c {
			if cutc {
				return s[0:i], s[i+1:len(s)]
			}
			return s[0:i], s[i:len(s)]
		}
	}
	return s, ""
}

// BUG(rsc): ParseURL should canonicalize the path,
// removing unnecessary . and .. elements.

// ParseURL parses rawurl into a URL structure.
// The string rawurl is assumed not to have a #fragment suffix.
// (Web browsers strip #fragment before sending the URL to a web server.)
func ParseURL(rawurl string) (url *URL, err *os.Error) {
	if rawurl == "" {
		return nil, BadURL
	}
	url = new(URL);
	url.Raw = rawurl;

	// split off possible leading "http:", "mailto:", etc.
	var path string;
	if url.Scheme, path, err = getscheme(rawurl); err != nil {
		return nil, err
	}
	url.RawPath = path;

	// RFC 2396: a relative URI (no scheme) has a ?query,
	// but absolute URIs only have query if path begins with /
	if url.Scheme == "" || len(path) > 0 && path[0] == '/' {
		path, url.Query = split(path, '?', true);
		if url.Query, err = URLUnescape(url.Query); err != nil {
			return nil, err
		}
	}

	// Maybe path is //authority/path
	if len(path) > 2 && path[0:2] == "//" {
		url.Authority, path = split(path[2:len(path)], '/', false);
	}

	// If there's no @, split's default is wrong.  Check explicitly.
	if strings.Index(url.Authority, "@") < 0 {
		url.Host = url.Authority;
	} else {
		url.Userinfo, url.Host = split(url.Authority, '@', true);
	}

	// What's left is the path.
	// TODO: Canonicalize (remove . and ..)?
	if url.Path, err = URLUnescape(path); err != nil {
		return nil, err
	}

	return url, nil
}

// ParseURLReference is like ParseURL but allows a trailing #fragment.
func ParseURLReference(rawurlref string) (url *URL, err *os.Error) {
	// Cut off #frag.
	rawurl, frag := split(rawurlref, '#', true);
	if url, err = ParseURL(rawurl); err != nil {
		return nil, err
	}
	if url.Fragment, err = URLUnescape(frag); err != nil {
		return nil, err
	}
	return url, nil
}

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

// Parse URLs (actually URIs, but that seems overly pedantic).
// TODO(rsc): Add tests.

package http

import (
	"os";
	"strings"
)

// Errors introduced by ParseURL.
var (
	BadURL = os.NewError("bad url syntax")
)

func ishex(c byte) bool {
	switch {
	case '0' <= c && c <= '9':
		return true;
	case 'a' <= c && c <= 'f':
		return true;
	case 'A' <= c && c <= 'F':
		return true;
	}
	return false
}

func unhex(c byte) byte {
	switch {
	case '0' <= c && c <= '9':
		return c - '0';
	case 'a' <= c && c <= 'f':
		return c - 'a' + 10;
	case 'A' <= c && c <= 'F':
		return c - 'A' + 10;
	}
	return 0
}

// URLUnescape unescapes a URL-encoded string,
// converting %AB into the byte 0xAB.
// It returns a BadURL error if any % is not followed
// by two hexadecimal digits.
func URLUnescape(s string) (string, *os.Error) {
	// Count %, check that they're well-formed.
	n := 0;
	for i := 0; i < len(s); {
		if s[i] == '%' {
			n++;
			if !ishex(s[i+1]) || !ishex(s[i+2]) {
				return "", BadURL;
			}
			i += 3
		} else {
			i++
		}
	}

	if n == 0 {
		return s, nil
	}

	t := make([]byte, len(s)-2*n);
	j := 0;
	for i := 0; i < len(s); {
		if s[i] == '%' {
			t[j] = unhex(s[i+1]) << 4 | unhex(s[i+2]);
			j++;
			i += 3;
		} else {
			t[j] = s[i];
			j++;
			i++;
		}
	}
	return string(t), nil;
}

// A URL represents a parsed URL (technically, a URI reference).
// The general form represented is:
//	scheme://[userinfo@]host/path[?query][#fragment]
type URL struct {
	Raw string;		// the original string
	Scheme string;		// scheme
	RawPath string;		// //[userinfo@]host/path[?query][#fragment]
	Authority string;	// [userinfo@]host
	Userinfo string;	// userinfo
	Host string;		// host
	Path string;		// /path
	Query string;		// query
	Fragment string;	// fragment
}

// Maybe rawurl is of the form scheme:path.
// (Scheme must be [a-zA-Z][a-zA-Z0-9+-.]*)
// If so, return scheme, path; else return "", rawurl.
func getscheme(rawurl string) (scheme, path string, err *os.Error) {
	for i := 0; i < len(rawurl); i++ {
		c := rawurl[i];
		switch {
		case 'a' <= c && c <= 'z' ||'A' <= c && c <= 'Z':
			// do nothing
		case '0' <= c && c <= '9' || c == '+' || c == '-' || c == '.':
			if i == 0 {
				return "", rawurl, nil
			}
		case c == ':':
			if i == 0 {
				return "", "", BadURL
			}
			return rawurl[0:i], rawurl[i+1:len(rawurl)], nil
		}
	}
	return "", rawurl, nil
}

// Maybe s is of the form t c u.
// If so, return t, c u (or t, u if cutc == true).
// If not, return s, "".
func split(s string, c byte, cutc bool) (string, string) {
	for i := 0; i < len(s); i++ {
		if s[i] == c {
			if cutc {
				return s[0:i], s[i+1:len(s)]
			}
			return s[0:i], s[i:len(s)]
		}
	}
	return s, ""
}

// BUG(rsc): ParseURL should canonicalize the path,
// removing unnecessary . and .. elements.

// ParseURL parses rawurl into a URL structure.
// The string rawurl is assumed not to have a #fragment suffix.
// (Web browsers strip #fragment before sending the URL to a web server.)
func ParseURL(rawurl string) (url *URL, err *os.Error) {
	if rawurl == "" {
		return nil, BadURL
	}
	url = new(URL);
	url.Raw = rawurl;

	// split off possible leading "http:", "mailto:", etc.
	var path string;
	if url.Scheme, path, err = getscheme(rawurl); err != nil {
		return nil, err
	}
	url.RawPath = path;

	// RFC 2396: a relative URI (no scheme) has a ?query,
	// but absolute URIs only have query if path begins with /
	if url.Scheme == "" || len(path) > 0 && path[0] == '/' {
		path, url.Query = split(path, '?', true);
		if url.Query, err = URLUnescape(url.Query); err != nil {
			return nil, err
		}
	}

	// Maybe path is //authority/path
	if len(path) > 2 && path[0:2] == "//" {
		url.Authority, path = split(path[2:len(path)], '/', false);
	}

	// If there's no @, split's default is wrong.  Check explicitly.
	if strings.Index(url.Authority, "@") < 0 {
		url.Host = url.Authority;
	} else {
		url.Userinfo, url.Host = split(url.Authority, '@', true);
	}

	// What's left is the path.
	// TODO: Canonicalize (remove . and ..)?
	if url.Path, err = URLUnescape(path); err != nil {
		return nil, err
	}

	return url, nil
}

// ParseURLReference is like ParseURL but allows a trailing #fragment.
func ParseURLReference(rawurlref string) (url *URL, err *os.Error) {
	// Cut off #frag.
	rawurl, frag := split(rawurlref, '#', true);
	if url, err = ParseURL(rawurl); err != nil {
		return nil, err
	}
	if url.Fragment, err = URLUnescape(frag); err != nil {
		return nil, err
	}
	return url, nil
}

<|endoftext|>