<commit_before>/*
Copyright 2016 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package e2e_node

import (
	"fmt"
	"strconv"
	"time"

	"github.com/golang/glog"
	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/api/resource"
	"k8s.io/kubernetes/test/e2e/framework"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

// Eviction Policy is described here:
// https://github.com/kubernetes/kubernetes/blob/master/docs/proposals/kubelet-eviction.md

var _ = framework.KubeDescribe("MemoryEviction [Slow] [Serial] [Disruptive]", func() {
	f := framework.NewDefaultFramework("eviction-test")

	Context("when there is memory pressure", func() {
		It("should evict pods in the correct order (besteffort first, then burstable, then guaranteed)", func() {
			By("creating a guaranteed pod, a burstable pod, and a besteffort pod.")

			// A pod is guaranteed only when requests and limits are specified for all the containers and they are equal.
			guaranteed := createMemhogPod(f, "guaranteed-", "guaranteed", api.ResourceRequirements{
				Requests: api.ResourceList{
					"cpu":    resource.MustParse("100m"),
					"memory": resource.MustParse("100Mi"),
				},
				Limits: api.ResourceList{
					"cpu":    resource.MustParse("100m"),
					"memory": resource.MustParse("100Mi"),
				}})

			// A pod is burstable if limits and requests do not match across all containers.
			burstable := createMemhogPod(f, "burstable-", "burstable", api.ResourceRequirements{
				Requests: api.ResourceList{
					"cpu":    resource.MustParse("100m"),
					"memory": resource.MustParse("100Mi"),
				}})

			// A pod is besteffort if none of its containers have specified any requests or limits.
			besteffort := createMemhogPod(f, "besteffort-", "besteffort", api.ResourceRequirements{})

			// We poll until timeout or all pods are killed.
			// Inside the func, we check that all pods are in a valid phase with
			// respect to the eviction order of best effort, then burstable, then guaranteed.
			By("polling the Status.Phase of each pod and checking for violations of the eviction order.")
			Eventually(func() error {

				gteed, gtErr := f.Client.Pods(f.Namespace.Name).Get(guaranteed.Name)
				framework.ExpectNoError(gtErr, fmt.Sprintf("getting pod %s", guaranteed.Name))
				gteedPh := gteed.Status.Phase

				burst, buErr := f.Client.Pods(f.Namespace.Name).Get(burstable.Name)
				framework.ExpectNoError(buErr, fmt.Sprintf("getting pod %s", burstable.Name))
				burstPh := burst.Status.Phase

				best, beErr := f.Client.Pods(f.Namespace.Name).Get(besteffort.Name)
				framework.ExpectNoError(beErr, fmt.Sprintf("getting pod %s", besteffort.Name))
				bestPh := best.Status.Phase

				glog.Infof("pod phase: guaranteed: %v, burstable: %v, besteffort: %v", gteedPh, burstPh, bestPh)

				if bestPh == api.PodRunning {
					Expect(burstPh).NotTo(Equal(api.PodFailed), "burstable pod failed before best effort pod")
					Expect(gteedPh).NotTo(Equal(api.PodFailed), "guaranteed pod failed before best effort pod")
				} else if burstPh == api.PodRunning {
					Expect(gteedPh).NotTo(Equal(api.PodFailed), "guaranteed pod failed before burstable pod")
				}

				// When both besteffort and burstable have been evicted, the test has completed.
				if bestPh == api.PodFailed && burstPh == api.PodFailed {
					return nil
				}
				return fmt.Errorf("besteffort and burstable have not yet both been evicted.")

			}, 60*time.Minute, 5*time.Second).Should(BeNil())

			// Wait for the memory pressure condition to disappear from the node status before continuing.
			Eventually(func() error {
				nodeList, err := f.Client.Nodes().List(api.ListOptions{})
				if err != nil {
					return fmt.Errorf("tried to get node list but got error: %v", err)
				}
				// Assuming that there is only one node, because this is a node e2e test.
				if len(nodeList.Items) != 1 {
					return fmt.Errorf("expected 1 node, but see %d. List: %v", len(nodeList.Items), nodeList.Items)
				}
				node := nodeList.Items[0]
				_, pressure := api.GetNodeCondition(&node.Status, api.NodeMemoryPressure)
				if pressure != nil && pressure.Status == api.ConditionTrue {
					return fmt.Errorf("node is still reporting memory pressure condition: %s", pressure)
				}
				return nil
			}, 5*time.Minute, 15*time.Second).Should(BeNil())

			// Check available memory after condition disappears, just in case:
			// Wait for available memory to decrease to a reasonable level before ending the test.
			// This helps prevent interference with tests that start immediately after this one.
			By("waiting for available memory to decrease to a reasonable level before ending the test.")
			Eventually(func() error {
				summary, err := getNodeSummary()
				if err != nil {
					return err
				}
				if summary.Node.Memory.AvailableBytes == nil {
					return fmt.Errorf("summary.Node.Memory.AvailableBytes was nil, cannot get memory stats.")
				}
				if summary.Node.Memory.WorkingSetBytes == nil {
					return fmt.Errorf("summary.Node.Memory.WorkingSetBytes was nil, cannot get memory stats.")
				}
				avail := *summary.Node.Memory.AvailableBytes
				wset := *summary.Node.Memory.WorkingSetBytes

				// memory limit = avail + wset
				limit := avail + wset
				halflimit := limit / 2

				// Wait for at least half of memory limit to be available
				if avail >= halflimit {
					return nil
				}
				return fmt.Errorf("current available memory is: %d bytes. Expected at least %d bytes available.", avail, halflimit)
			}, 5*time.Minute, 15*time.Second).Should(BeNil())

			// TODO(mtaufen): 5 minute wait to stop flaky test bleeding while we figure out what is actually going on.
			//                If related to pressure transition period in eviction manager, probably only need to wait
			//                just over 30s becasue that is the transition period set for node e2e tests. But since we
			//                know 5 min works and we don't know if transition period is the problem, wait 5 min for now.
			time.Sleep(5 * time.Minute)

			// Finally, try starting a new pod and wait for it to be scheduled and running.
			// This is the final check to try to prevent interference with subsequent tests.
			podName := "admit-best-effort-pod"
			f.PodClient().CreateSync(&api.Pod{
				ObjectMeta: api.ObjectMeta{
					Name: podName,
				},
				Spec: api.PodSpec{
					RestartPolicy: api.RestartPolicyNever,
					Containers: []api.Container{
						{
							Image: ImageRegistry[pauseImage],
							Name:  podName,
						},
					},
				},
			})
		})
	})
})

func createMemhogPod(f *framework.Framework, genName string, ctnName string, res api.ResourceRequirements) *api.Pod {
	env := []api.EnvVar{
		{
			Name: "MEMORY_LIMIT",
			ValueFrom: &api.EnvVarSource{
				ResourceFieldRef: &api.ResourceFieldSelector{
					Resource: "limits.memory",
				},
			},
		},
	}

	// If there is a limit specified, pass 80% of it for -mem-total, otherwise use the downward API
	// to pass limits.memory, which will be the total memory available.
	// This helps prevent a guaranteed pod from triggering an OOM kill due to it's low memory limit,
	// which will cause the test to fail inappropriately.
	var memLimit string
	if limit, ok := res.Limits["memory"]; ok {
		memLimit = strconv.Itoa(int(
			float64(limit.Value()) * 0.8))
	} else {
		memLimit = "$(MEMORY_LIMIT)"
	}

	pod := &api.Pod{
		ObjectMeta: api.ObjectMeta{
			GenerateName: genName,
		},
		Spec: api.PodSpec{
			RestartPolicy: api.RestartPolicyNever,
			Containers: []api.Container{
				{
					Name:            ctnName,
					Image:           "gcr.io/google-containers/stress:v1",
					ImagePullPolicy: "Always",
					Env:             env,
					// 60 min timeout * 60s / tick per 10s = 360 ticks before timeout => ~11.11Mi/tick
					// to fill ~4Gi of memory, so initial ballpark 12Mi/tick.
					// We might see flakes due to timeout if the total memory on the nodes increases.
					Args:      []string{"-mem-alloc-size", "12Mi", "-mem-alloc-sleep", "10s", "-mem-total", memLimit},
					Resources: res,
				},
			},
		},
	}
	// The generated pod.Name will be on the pod spec returned by CreateSync
	pod = f.PodClient().CreateSync(pod)
	glog.Infof("pod created with name: %s", pod.Name)
	return pod
}
<commit_msg>Move wait for pressure to subside to AfterEach so we still wait if the test for eviction order fails<commit_after>/*
Copyright 2016 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package e2e_node

import (
	"fmt"
	"strconv"
	"time"

	"github.com/golang/glog"
	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/api/resource"
	"k8s.io/kubernetes/test/e2e/framework"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

// Eviction Policy is described here:
// https://github.com/kubernetes/kubernetes/blob/master/docs/proposals/kubelet-eviction.md

var _ = framework.KubeDescribe("MemoryEviction [Slow] [Serial] [Disruptive]", func() {
	f := framework.NewDefaultFramework("eviction-test")

	Context("when there is memory pressure", func() {
		AfterEach(func() {
			// Wait for the memory pressure condition to disappear from the node status before continuing.
			By("waiting for the memory pressure condition on the node to disappear before ending the test.")
			Eventually(func() error {
				nodeList, err := f.Client.Nodes().List(api.ListOptions{})
				if err != nil {
					return fmt.Errorf("tried to get node list but got error: %v", err)
				}
				// Assuming that there is only one node, because this is a node e2e test.
				if len(nodeList.Items) != 1 {
					return fmt.Errorf("expected 1 node, but see %d. List: %v", len(nodeList.Items), nodeList.Items)
				}
				node := nodeList.Items[0]
				_, pressure := api.GetNodeCondition(&node.Status, api.NodeMemoryPressure)
				if pressure != nil && pressure.Status == api.ConditionTrue {
					return fmt.Errorf("node is still reporting memory pressure condition: %s", pressure)
				}
				return nil
			}, 5*time.Minute, 15*time.Second).Should(BeNil())

			// Check available memory after condition disappears, just in case:
			// Wait for available memory to decrease to a reasonable level before ending the test.
			// This helps prevent interference with tests that start immediately after this one.
			By("waiting for available memory to decrease to a reasonable level before ending the test.")
			Eventually(func() error {
				summary, err := getNodeSummary()
				if err != nil {
					return err
				}
				if summary.Node.Memory.AvailableBytes == nil {
					return fmt.Errorf("summary.Node.Memory.AvailableBytes was nil, cannot get memory stats.")
				}
				if summary.Node.Memory.WorkingSetBytes == nil {
					return fmt.Errorf("summary.Node.Memory.WorkingSetBytes was nil, cannot get memory stats.")
				}
				avail := *summary.Node.Memory.AvailableBytes
				wset := *summary.Node.Memory.WorkingSetBytes

				// memory limit = avail + wset
				limit := avail + wset
				halflimit := limit / 2

				// Wait for at least half of memory limit to be available
				if avail >= halflimit {
					return nil
				}
				return fmt.Errorf("current available memory is: %d bytes. Expected at least %d bytes available.", avail, halflimit)
			}, 5*time.Minute, 15*time.Second).Should(BeNil())

			// TODO(mtaufen): 5 minute wait to stop flaky test bleeding while we figure out what is actually going on.
			//                If related to pressure transition period in eviction manager, probably only need to wait
			//                just over 30s becasue that is the transition period set for node e2e tests. But since we
			//                know 5 min works and we don't know if transition period is the problem, wait 5 min for now.
			time.Sleep(5 * time.Minute)

			// Finally, try starting a new pod and wait for it to be scheduled and running.
			// This is the final check to try to prevent interference with subsequent tests.
			podName := "admit-best-effort-pod"
			f.PodClient().CreateSync(&api.Pod{
				ObjectMeta: api.ObjectMeta{
					Name: podName,
				},
				Spec: api.PodSpec{
					RestartPolicy: api.RestartPolicyNever,
					Containers: []api.Container{
						{
							Image: ImageRegistry[pauseImage],
							Name:  podName,
						},
					},
				},
			})
		})

		It("should evict pods in the correct order (besteffort first, then burstable, then guaranteed)", func() {
			By("creating a guaranteed pod, a burstable pod, and a besteffort pod.")

			// A pod is guaranteed only when requests and limits are specified for all the containers and they are equal.
			guaranteed := createMemhogPod(f, "guaranteed-", "guaranteed", api.ResourceRequirements{
				Requests: api.ResourceList{
					"cpu":    resource.MustParse("100m"),
					"memory": resource.MustParse("100Mi"),
				},
				Limits: api.ResourceList{
					"cpu":    resource.MustParse("100m"),
					"memory": resource.MustParse("100Mi"),
				}})

			// A pod is burstable if limits and requests do not match across all containers.
			burstable := createMemhogPod(f, "burstable-", "burstable", api.ResourceRequirements{
				Requests: api.ResourceList{
					"cpu":    resource.MustParse("100m"),
					"memory": resource.MustParse("100Mi"),
				}})

			// A pod is besteffort if none of its containers have specified any requests or limits.
			besteffort := createMemhogPod(f, "besteffort-", "besteffort", api.ResourceRequirements{})

			// We poll until timeout or all pods are killed.
			// Inside the func, we check that all pods are in a valid phase with
			// respect to the eviction order of best effort, then burstable, then guaranteed.
			By("polling the Status.Phase of each pod and checking for violations of the eviction order.")
			Eventually(func() error {

				gteed, gtErr := f.Client.Pods(f.Namespace.Name).Get(guaranteed.Name)
				framework.ExpectNoError(gtErr, fmt.Sprintf("getting pod %s", guaranteed.Name))
				gteedPh := gteed.Status.Phase

				burst, buErr := f.Client.Pods(f.Namespace.Name).Get(burstable.Name)
				framework.ExpectNoError(buErr, fmt.Sprintf("getting pod %s", burstable.Name))
				burstPh := burst.Status.Phase

				best, beErr := f.Client.Pods(f.Namespace.Name).Get(besteffort.Name)
				framework.ExpectNoError(beErr, fmt.Sprintf("getting pod %s", besteffort.Name))
				bestPh := best.Status.Phase

				glog.Infof("pod phase: guaranteed: %v, burstable: %v, besteffort: %v", gteedPh, burstPh, bestPh)

				if bestPh == api.PodRunning {
					Expect(burstPh).NotTo(Equal(api.PodFailed), "burstable pod failed before best effort pod")
					Expect(gteedPh).NotTo(Equal(api.PodFailed), "guaranteed pod failed before best effort pod")
				} else if burstPh == api.PodRunning {
					Expect(gteedPh).NotTo(Equal(api.PodFailed), "guaranteed pod failed before burstable pod")
				}

				// When both besteffort and burstable have been evicted, the test has completed.
				if bestPh == api.PodFailed && burstPh == api.PodFailed {
					return nil
				}
				return fmt.Errorf("besteffort and burstable have not yet both been evicted.")

			}, 60*time.Minute, 5*time.Second).Should(BeNil())

		})
	})
})

func createMemhogPod(f *framework.Framework, genName string, ctnName string, res api.ResourceRequirements) *api.Pod {
	env := []api.EnvVar{
		{
			Name: "MEMORY_LIMIT",
			ValueFrom: &api.EnvVarSource{
				ResourceFieldRef: &api.ResourceFieldSelector{
					Resource: "limits.memory",
				},
			},
		},
	}

	// If there is a limit specified, pass 80% of it for -mem-total, otherwise use the downward API
	// to pass limits.memory, which will be the total memory available.
	// This helps prevent a guaranteed pod from triggering an OOM kill due to it's low memory limit,
	// which will cause the test to fail inappropriately.
	var memLimit string
	if limit, ok := res.Limits["memory"]; ok {
		memLimit = strconv.Itoa(int(
			float64(limit.Value()) * 0.8))
	} else {
		memLimit = "$(MEMORY_LIMIT)"
	}

	pod := &api.Pod{
		ObjectMeta: api.ObjectMeta{
			GenerateName: genName,
		},
		Spec: api.PodSpec{
			RestartPolicy: api.RestartPolicyNever,
			Containers: []api.Container{
				{
					Name:            ctnName,
					Image:           "gcr.io/google-containers/stress:v1",
					ImagePullPolicy: "Always",
					Env:             env,
					// 60 min timeout * 60s / tick per 10s = 360 ticks before timeout => ~11.11Mi/tick
					// to fill ~4Gi of memory, so initial ballpark 12Mi/tick.
					// We might see flakes due to timeout if the total memory on the nodes increases.
					Args:      []string{"-mem-alloc-size", "12Mi", "-mem-alloc-sleep", "10s", "-mem-total", memLimit},
					Resources: res,
				},
			},
		},
	}
	// The generated pod.Name will be on the pod spec returned by CreateSync
	pod = f.PodClient().CreateSync(pod)
	glog.Infof("pod created with name: %s", pod.Name)
	return pod
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"net/http"
	"runtime"
	"strconv"
	"strings"
	"time"
	"wpst.me/calf/config"
	"wpst.me/calf/storage"
)

var cmdTiring = &Command{
	UsageLine: "tiring -port 8964 -whiteList=\"127.0.0.1\"",
	Short:     "serve tiring http service",
	Long: `
serve tiring http service
`,
}

var (
	mport           = cmdTiring.Flag.Int("port", 8964, "tcp listen port")
	mReadTimeout    = cmdTiring.Flag.Int("readTimeout", 3, "connection read timeout in seconds")
	mMaxCpu         = cmdTiring.Flag.Int("maxCpu", 0, "maximum number of CPUs. 0 means all available CPUs")
	whiteListOption = cmdTiring.Flag.String("whiteList", "", "comma separated Ip addresses having write permission. No limit if empty.")
	whiteList       []string
)

func init() {
	cmdTiring.Run = runTiring
	cmdTiring.IsDebug = cmdTiring.Flag.Bool("debug", false, "enable debug mode")
}

func roofsHandler(w http.ResponseWriter, r *http.Request) {
	m := make(map[string]interface{})
	m["roofs"] = config.Sections()
	writeJsonQuiet(w, r, m)
}

func browseHandler(w http.ResponseWriter, r *http.Request) {
	roof := r.FormValue("roof")
	// log.Printf("browse roof: %s", roof)
	var (
		limit uint64
		page  uint64
	)

	if str := r.FormValue("rows"); str != "" {
		limit, _ = strconv.ParseUint(str, 10, 32)
		if limit < 1 {
			limit = 1
		}
	} else {
		limit = 20
	}

	if str := r.FormValue("page"); str != "" {
		page, _ = strconv.ParseUint(str, 10, 32)
	}
	if page < 1 {
		page = 1
	}

	offset := limit * (page - 1)

	sort := make(map[string]int)
	sort_name := r.FormValue("sort_name")
	sort_order := r.FormValue("sort_order")
	if sort_name != "" {
		var o int
		if strings.ToUpper(sort_order) == "ASC" {
			o = storage.ASCENDING
		} else {
			o = storage.DESCENDING
		}
		sort[sort_name] = o
	}

	mw := storage.NewMetaWrapper(roof)
	t, err := mw.Count()
	if err != nil {
		log.Printf("ERROR: %s", err)
		writeJsonError(w, r, err)
		return
	}
	a, err := mw.Browse(int(limit), int(offset), sort)
	if err != nil {
		log.Printf("ERROR: %s", err)
		writeJsonError(w, r, err)
		return
	}
	m := make(map[string]interface{})
	m["rows"] = limit
	m["page"] = page

	m["data"] = a
	m["total"] = t

	thumb_path := config.GetValue(roof, "thumb_path")
	m["thumb_path"] = strings.TrimSuffix(thumb_path, "/") + "/"
	// log.Printf("total: %d\n", t)
	m["version"] = VERSION
	writeJsonQuiet(w, r, m)
}

func storeHandler(w http.ResponseWriter, r *http.Request) {
	switch r.Method {
	case "GET":
		GetOrHeadHandler(w, r, true)
	case "HEAD":
		GetOrHeadHandler(w, r, false)
	case "DELETE":
		secure(whiteList, DeleteHandler)(w, r)
	case "POST":
		secure(whiteList, PostHandler)(w, r)
	}
}

func GetOrHeadHandler(w http.ResponseWriter, r *http.Request, isGetMethod bool) {
	// TODO:
}
func PostHandler(w http.ResponseWriter, r *http.Request) {
	entries, err := storage.StoredRequest(r)

	if err != nil {
		log.Printf("ERROR: %s", err)
		writeJsonError(w, r, err)
		return
	}
	// log.Print(entries[0].Path)
	m := make(map[string]interface{})

	// log.Printf("post new id: %v, size: %d, path: %v\n", entry.Id, entry.Size, entry.Path)

	// m["id"] = entry.Id.String()
	// m["path"] = entry.Path
	// m["size"] = entry.Size

	m["status"] = "ok"
	m["data"] = entries

	writeJsonQuiet(w, r, m)
}
func DeleteHandler(w http.ResponseWriter, r *http.Request) {
	err := storage.DeleteRequest(r)
	if err != nil {
		log.Printf("ERROR: %s", err)
		writeJsonError(w, r, err)
		return
	}

	m := make(map[string]interface{})
	m["status"] = "ok"
	writeJsonQuiet(w, r, m)
}

func tokenHandler(w http.ResponseWriter, r *http.Request) {
	token, err := storage.TokenRequestNew(r)
	if err != nil {
		log.Printf("ERROR: %s", err)
		writeJsonError(w, r, err)
		return
	}

	m := make(map[string]interface{})
	m["status"] = "ok"
	m["token"] = token.String()
	writeJsonQuiet(w, r, m)
}

func ticketHandler(w http.ResponseWriter, r *http.Request) {
	m := make(map[string]interface{})
	if r.Method == "POST" {
		token, err := storage.TicketRequestNew(r)
		if err != nil {
			log.Printf("ERROR: %s", err)
			writeJsonError(w, r, err)
			return
		}
		m["token"] = token.String()
	} else if r.Method == "GET" {
		ticket, err := storage.TicketRequestLoad(r)
		if err != nil {
			log.Printf("ERROR: %s", err)
			writeJsonError(w, r, err)
			return
		}
		m["ticket"] = ticket
	}

	if len(m) > 0 {
		m["status"] = "ok"
	}
	writeJsonQuiet(w, r, m)
}

func runTiring(args []string) bool {
	if *mMaxCpu < 1 {
		*mMaxCpu = runtime.NumCPU()
	}
	runtime.GOMAXPROCS(*mMaxCpu)
	// fmt.Println(cmdTiring.Name())

	if *whiteListOption != "" {
		whiteList = strings.Split(*whiteListOption, ",")
	}

	var e error
	http.HandleFunc("/imsto/", storeHandler)
	http.HandleFunc("/imsto/meta", browseHandler)
	http.HandleFunc("/imsto/roofs", roofsHandler)
	http.HandleFunc("/imsto/token", tokenHandler)
	http.HandleFunc("/imsto/ticket", ticketHandler)

	log.Print("Start Tiring service ", VERSION, " at port ", strconv.Itoa(*mport))
	srv := &http.Server{
		Addr:        ":" + strconv.Itoa(*mport),
		Handler:     http.DefaultServeMux,
		ReadTimeout: time.Duration(*mReadTimeout) * time.Second,
	}
	e = srv.ListenAndServe()
	if e != nil {
		log.Printf("Fail to start:%s\n", e)
	}

	return true
}
<commit_msg>fixes browse return struct<commit_after>package main

import (
	"log"
	"net/http"
	"runtime"
	"strconv"
	"strings"
	"time"
	"wpst.me/calf/config"
	"wpst.me/calf/storage"
)

var cmdTiring = &Command{
	UsageLine: "tiring -port 8964 -whiteList=\"127.0.0.1\"",
	Short:     "serve tiring http service",
	Long: `
serve tiring http service
`,
}

var (
	mport           = cmdTiring.Flag.Int("port", 8964, "tcp listen port")
	mReadTimeout    = cmdTiring.Flag.Int("readTimeout", 3, "connection read timeout in seconds")
	mMaxCpu         = cmdTiring.Flag.Int("maxCpu", 0, "maximum number of CPUs. 0 means all available CPUs")
	whiteListOption = cmdTiring.Flag.String("whiteList", "", "comma separated Ip addresses having write permission. No limit if empty.")
	whiteList       []string
)

func init() {
	cmdTiring.Run = runTiring
	cmdTiring.IsDebug = cmdTiring.Flag.Bool("debug", false, "enable debug mode")
}

func roofsHandler(w http.ResponseWriter, r *http.Request) {
	m := make(map[string]interface{})
	m["roofs"] = config.Sections()
	writeJsonQuiet(w, r, m)
}

func browseHandler(w http.ResponseWriter, r *http.Request) {
	roof := r.FormValue("roof")
	// log.Printf("browse roof: %s", roof)
	var (
		limit uint64
		page  uint64
	)

	if str := r.FormValue("rows"); str != "" {
		limit, _ = strconv.ParseUint(str, 10, 32)
		if limit < 1 {
			limit = 1
		}
	} else {
		limit = 20
	}

	if str := r.FormValue("page"); str != "" {
		page, _ = strconv.ParseUint(str, 10, 32)
	}
	if page < 1 {
		page = 1
	}

	offset := limit * (page - 1)

	sort := make(map[string]int)
	sort_name := r.FormValue("sort_name")
	sort_order := r.FormValue("sort_order")
	if sort_name != "" {
		var o int
		if strings.ToUpper(sort_order) == "ASC" {
			o = storage.ASCENDING
		} else {
			o = storage.DESCENDING
		}
		sort[sort_name] = o
	}

	mw := storage.NewMetaWrapper(roof)
	t, err := mw.Count()
	if err != nil {
		log.Printf("ERROR: %s", err)
		writeJsonError(w, r, err)
		return
	}
	a, err := mw.Browse(int(limit), int(offset), sort)
	if err != nil {
		log.Printf("ERROR: %s", err)
		writeJsonError(w, r, err)
		return
	}
	m := make(map[string]interface{})
	m["status"] = "ok"
	m["rows"] = limit
	m["page"] = page

	m["data"] = a
	m["total"] = t

	thumb_path := config.GetValue(roof, "thumb_path")
	m["thumb_path"] = strings.TrimSuffix(thumb_path, "/") + "/"
	// log.Printf("total: %d\n", t)
	m["version"] = VERSION
	writeJsonQuiet(w, r, m)
}

func storeHandler(w http.ResponseWriter, r *http.Request) {
	switch r.Method {
	case "GET":
		GetOrHeadHandler(w, r, true)
	case "HEAD":
		GetOrHeadHandler(w, r, false)
	case "DELETE":
		secure(whiteList, DeleteHandler)(w, r)
	case "POST":
		secure(whiteList, PostHandler)(w, r)
	}
}

func GetOrHeadHandler(w http.ResponseWriter, r *http.Request, isGetMethod bool) {
	// TODO:
}
func PostHandler(w http.ResponseWriter, r *http.Request) {
	entries, err := storage.StoredRequest(r)

	if err != nil {
		log.Printf("ERROR: %s", err)
		writeJsonError(w, r, err)
		return
	}
	// log.Print(entries[0].Path)
	m := make(map[string]interface{})

	// log.Printf("post new id: %v, size: %d, path: %v\n", entry.Id, entry.Size, entry.Path)

	// m["id"] = entry.Id.String()
	// m["path"] = entry.Path
	// m["size"] = entry.Size

	m["status"] = "ok"
	m["data"] = entries

	writeJsonQuiet(w, r, m)
}
func DeleteHandler(w http.ResponseWriter, r *http.Request) {
	err := storage.DeleteRequest(r)
	if err != nil {
		log.Printf("ERROR: %s", err)
		writeJsonError(w, r, err)
		return
	}

	m := make(map[string]interface{})
	m["status"] = "ok"
	writeJsonQuiet(w, r, m)
}

func tokenHandler(w http.ResponseWriter, r *http.Request) {
	token, err := storage.TokenRequestNew(r)
	if err != nil {
		log.Printf("ERROR: %s", err)
		writeJsonError(w, r, err)
		return
	}

	m := make(map[string]interface{})
	m["status"] = "ok"
	m["token"] = token.String()
	writeJsonQuiet(w, r, m)
}

func ticketHandler(w http.ResponseWriter, r *http.Request) {
	m := make(map[string]interface{})
	if r.Method == "POST" {
		token, err := storage.TicketRequestNew(r)
		if err != nil {
			log.Printf("ERROR: %s", err)
			writeJsonError(w, r, err)
			return
		}
		m["token"] = token.String()
	} else if r.Method == "GET" {
		ticket, err := storage.TicketRequestLoad(r)
		if err != nil {
			log.Printf("ERROR: %s", err)
			writeJsonError(w, r, err)
			return
		}
		m["ticket"] = ticket
	}

	if len(m) > 0 {
		m["status"] = "ok"
	}
	writeJsonQuiet(w, r, m)
}

func runTiring(args []string) bool {
	if *mMaxCpu < 1 {
		*mMaxCpu = runtime.NumCPU()
	}
	runtime.GOMAXPROCS(*mMaxCpu)
	// fmt.Println(cmdTiring.Name())

	if *whiteListOption != "" {
		whiteList = strings.Split(*whiteListOption, ",")
	}

	var e error
	http.HandleFunc("/imsto/", storeHandler)
	http.HandleFunc("/imsto/meta", browseHandler)
	http.HandleFunc("/imsto/roofs", roofsHandler)
	http.HandleFunc("/imsto/token", tokenHandler)
	http.HandleFunc("/imsto/ticket", ticketHandler)

	log.Print("Start Tiring service ", VERSION, " at port ", strconv.Itoa(*mport))
	srv := &http.Server{
		Addr:        ":" + strconv.Itoa(*mport),
		Handler:     http.DefaultServeMux,
		ReadTimeout: time.Duration(*mReadTimeout) * time.Second,
	}
	e = srv.ListenAndServe()
	if e != nil {
		log.Printf("Fail to start:%s\n", e)
	}

	return true
}
<|endoftext|>


<commit_before>// +build integrationtest

package integrationtest

import (
	"testing"
	"time"

	"github.com/portworx/torpedo/drivers/scheduler"
	"github.com/stretchr/testify/require"
)

func testSnapshotRestore(t *testing.T) {
	t.Run("simpleSnapshotRestoreTest", simpleSnapshotRestoreTest)
	t.Run("groupSnapshotRestoreTest", groupSnapshotRestoreTest)
	// Disable cloudsnapRestore tests for now
	t.Run("cloudSnapshotRestoreTest", cloudSnapshotRestoreTest)
	t.Run("groupCloudSnapshotRestoreTest", groupCloudSnapshotRestoreTest)
}

func createInPlaceRestore(t *testing.T, namespace string, appKeys []string) []*scheduler.Context {
	ctxs, err := schedulerDriver.Schedule(namespace,
		scheduler.ScheduleOptions{AppKeys: appKeys})
	require.NoError(t, err, "Error scheduling task")
	require.Equal(t, 1, len(ctxs), "Only one task should have started")
	return ctxs
}

func verifyInPlaceSnapshotRestore(t *testing.T, ctx []*scheduler.Context, startTime time.Time, timeout time.Duration) {
	err := schedulerDriver.WaitForRunning(ctx[0], timeout, defaultWaitInterval)
	require.NoError(t, err, "Error waiting for task")
	err = schedulerDriver.ValidateVolumeSnapshotRestore(ctx[0], startTime)
	require.NoError(t, err, "Error validating volumesnapshotRestore")
}

func simpleSnapshotRestoreTest(t *testing.T) {
	// foldername + name as namespaces
	snapCtx, err := schedulerDriver.Schedule("splocal",
		scheduler.ScheduleOptions{AppKeys: []string{"mysql-snap-restore"}})
	require.NoError(t, err, "Error scheduling task")
	require.Equal(t, 1, len(snapCtx), "Only one task should have started")
	verifySnapshot(t, snapCtx, "mysql-data", defaultWaitTimeout)
	startTime := time.Now()
	restoreCtx := createInPlaceRestore(t, "splocal", []string{"mysql-snap-inplace-restore"})
	verifyInPlaceSnapshotRestore(t, restoreCtx, startTime, defaultWaitTimeout)

	// cleanup test
	destroyAndWait(t, snapCtx)
	destroyAndWait(t, restoreCtx)
}

func groupSnapshotRestoreTest(t *testing.T) {
	snapCtx, err := schedulerDriver.Schedule("spgroup",
		scheduler.ScheduleOptions{AppKeys: []string{"mysql-2-pvc"}})
	require.NoError(t, err, "Error scheduling task")
	require.Len(t, snapCtx, 1, "Only one task should have started")
	verifyGroupSnapshot(t, snapCtx[0], defaultWaitTimeout)

	err = schedulerDriver.AddTasks(snapCtx[0],
		scheduler.ScheduleOptions{AppKeys: []string{"mysql-localsnap-group"}})
	require.NoError(t, err, "Error scheduling task")

	// restore local groupsnapshot
	startTime := time.Now()
	restoreCtx := createInPlaceRestore(t, "spgroup", []string{"mysql-snap-inplace-group-restore"})
	verifyInPlaceSnapshotRestore(t, restoreCtx, startTime, defaultWaitTimeout)

	// cleanup test
	destroyAndWait(t, snapCtx)
	destroyAndWait(t, restoreCtx)
}

func cloudSnapshotRestoreTest(t *testing.T) {
	t.Skip("Skipping CloudSnapRestore integration tests")
	snapCtx, err := schedulerDriver.Schedule("cslocal",
		scheduler.ScheduleOptions{AppKeys: []string{"mysql-cloudsnap-restore"}})
	require.NoError(t, err, "Error scheduling task")
	require.Equal(t, 1, len(snapCtx), "Only one task should have started")

	err = schedulerDriver.WaitForRunning(snapCtx[0], defaultWaitTimeout, defaultWaitInterval)
	require.NoError(t, err, "Error waiting for pod to get to running state")

	restoreCtx := createInPlaceRestore(t, "cslocal", []string{"mysql-snap-inplace-cloud-restore"})
	startTime := time.Now()
	verifyInPlaceSnapshotRestore(t, restoreCtx, startTime, defaultWaitTimeout)

	// cleanup test
	destroyAndWait(t, snapCtx)
	destroyAndWait(t, restoreCtx)
}

func groupCloudSnapshotRestoreTest(t *testing.T) {
	//TODO: add groupcloudsnap in place restore tests here
}
<commit_msg>enable cs inplace restore integration tests<commit_after>// +build integrationtest

package integrationtest

import (
	"testing"
	"time"

	"github.com/portworx/torpedo/drivers/scheduler"
	"github.com/stretchr/testify/require"
)

func testSnapshotRestore(t *testing.T) {
	t.Run("simpleSnapshotRestoreTest", simpleSnapshotRestoreTest)
	t.Run("groupSnapshotRestoreTest", groupSnapshotRestoreTest)
	// Disable cloudsnapRestore tests for now
	t.Run("cloudSnapshotRestoreTest", cloudSnapshotRestoreTest)
	t.Run("groupCloudSnapshotRestoreTest", groupCloudSnapshotRestoreTest)
}

func createInPlaceRestore(t *testing.T, namespace string, appKeys []string) []*scheduler.Context {
	ctxs, err := schedulerDriver.Schedule(namespace,
		scheduler.ScheduleOptions{AppKeys: appKeys})
	require.NoError(t, err, "Error scheduling task")
	require.Equal(t, 1, len(ctxs), "Only one task should have started")
	return ctxs
}

func verifyInPlaceSnapshotRestore(t *testing.T, ctx []*scheduler.Context, startTime time.Time, timeout time.Duration) {
	err := schedulerDriver.WaitForRunning(ctx[0], timeout, defaultWaitInterval)
	require.NoError(t, err, "Error waiting for task")
	err = schedulerDriver.ValidateVolumeSnapshotRestore(ctx[0], startTime)
	require.NoError(t, err, "Error validating volumesnapshotRestore")
}

func simpleSnapshotRestoreTest(t *testing.T) {
	// foldername + name as namespaces
	snapCtx, err := schedulerDriver.Schedule("splocal",
		scheduler.ScheduleOptions{AppKeys: []string{"mysql-snap-restore"}})
	require.NoError(t, err, "Error scheduling task")
	require.Equal(t, 1, len(snapCtx), "Only one task should have started")
	verifySnapshot(t, snapCtx, "mysql-data", defaultWaitTimeout)
	startTime := time.Now()
	restoreCtx := createInPlaceRestore(t, "splocal", []string{"mysql-snap-inplace-restore"})
	verifyInPlaceSnapshotRestore(t, restoreCtx, startTime, defaultWaitTimeout)

	// cleanup test
	destroyAndWait(t, snapCtx)
	destroyAndWait(t, restoreCtx)
}

func groupSnapshotRestoreTest(t *testing.T) {
	snapCtx, err := schedulerDriver.Schedule("spgroup",
		scheduler.ScheduleOptions{AppKeys: []string{"mysql-2-pvc"}})
	require.NoError(t, err, "Error scheduling task")
	require.Len(t, snapCtx, 1, "Only one task should have started")
	verifyGroupSnapshot(t, snapCtx[0], defaultWaitTimeout)

	err = schedulerDriver.AddTasks(snapCtx[0],
		scheduler.ScheduleOptions{AppKeys: []string{"mysql-localsnap-group"}})
	require.NoError(t, err, "Error scheduling task")

	// restore local groupsnapshot
	startTime := time.Now()
	restoreCtx := createInPlaceRestore(t, "spgroup", []string{"mysql-snap-inplace-group-restore"})
	verifyInPlaceSnapshotRestore(t, restoreCtx, startTime, defaultWaitTimeout)

	// cleanup test
	destroyAndWait(t, snapCtx)
	destroyAndWait(t, restoreCtx)
}

func cloudSnapshotRestoreTest(t *testing.T) {
	snapCtx, err := schedulerDriver.Schedule("cslocal",
		scheduler.ScheduleOptions{AppKeys: []string{"mysql-cloudsnap-restore"}})
	require.NoError(t, err, "Error scheduling task")
	require.Equal(t, 1, len(snapCtx), "Only one task should have started")

	err = schedulerDriver.WaitForRunning(snapCtx[0], defaultWaitTimeout, defaultWaitInterval)
	require.NoError(t, err, "Error waiting for pod to get to running state")

	restoreCtx := createInPlaceRestore(t, "cslocal", []string{"mysql-snap-inplace-cloud-restore"})
	startTime := time.Now()
	verifyInPlaceSnapshotRestore(t, restoreCtx, startTime, defaultWaitTimeout)

	// cleanup test
	destroyAndWait(t, snapCtx)
	destroyAndWait(t, restoreCtx)
}

func groupCloudSnapshotRestoreTest(t *testing.T) {
	//TODO: add groupcloudsnap in place restore tests here
}
<|endoftext|>


<commit_before>/*
   Nging is a toolbox for webmasters
   Copyright (C) 2018-present  Wenhui Shen <swh@admpub.com>

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU Affero 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 Affero General Public License for more details.

   You should have received a copy of the GNU Affero General Public License
   along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/

package term

import (
	"fmt"
	"log"
	"net/http"
	"net/url"
	"os"
	"path/filepath"

	"github.com/webx-top/echo"

	"github.com/admpub/nging/application/dbschema"
	"github.com/admpub/nging/application/handler"
	"github.com/admpub/nging/application/library/config"
	"github.com/admpub/nging/application/model"
	termConfig "github.com/admpub/web-terminal/config"
	termHandler "github.com/admpub/web-terminal/handler"
)

type TerminalParam struct {
	Query url.Values
	User  *dbschema.NgingSshUser
}

type key string

var contextKey key = `param`

func init() {
	handler.RegisterToGroup(`/term`, func(g echo.RouteRegister) {
		g.Route(`GET`, `/account`, AccountIndex)
		g.Route(`GET,POST`, `/account_add`, AccountAdd)
		g.Route(`GET,POST`, `/account_edit`, AccountEdit)
		g.Route(`GET,POST`, `/account_delete`, AccountDelete)
		g.Route(`GET`, `/client`, Client)
		g.Route(`GET,POST`, `/sftp`, Sftp)
		termHandler.ParamGet = func(ctx *termHandler.Context, name string) (value string) {
			/*
				defer func() {
					fmt.Println(`web-terminal: [param]`, name, `->`, value)
				}()
			// */
			var (
				param *TerminalParam
				val   interface{}
				ok    bool
			)
			if val, ok = ctx.Data.Load(contextKey); ok {
				param, ok = val.(*TerminalParam)
			}
			if !ok {
				param = &TerminalParam{
					Query: ctx.Request().URL.Query(),
				}

				id := param.Query.Get(`id`)
				if len(id) > 0 {
					m := model.NewSshUser(nil)
					err := m.Get(nil, `id`, id)
					if err == nil {
						param.User = m.NgingSshUser
					}
				}
				ctx.Data.Store(contextKey, param)
			}
			if param.User != nil {
				switch name {
				case `password`:
					return config.DefaultConfig.Decode(param.User.Password)
				case `user`:
					return param.User.Username
				case `protocol`:
					return param.User.Protocol
				case `hostname`:
					return param.User.Host
				case `port`:
					return fmt.Sprint(param.User.Port)
				case `privateKey`:
					return param.User.PrivateKey
				case `passphrase`:
					return config.DefaultConfig.Decode(param.User.Passphrase)
				case `charset`:
					if len(param.User.Charset) == 0 {
						return `UTF-8`
					}
					return param.User.Charset
				}
			}
			value = param.Query.Get(name)
			if name == `password` {
				value = config.DefaultConfig.Decode(value)
			}
			return value
		}
		termConfig.Default.APPRoot = handler.URLFor(`/client/`)
		termConfig.Default.Debug = config.DefaultConfig.Debug
		logDir := filepath.Join(echo.Wd(), `data/logs`)
		err := os.MkdirAll(logDir, os.ModePerm)
		if err != nil {
			log.Println(err)
		}
		termConfig.Default.LogDir = filepath.Join(logDir, `term`)
		termConfig.Default.ResourceDir = `public/xterm`
		termConfig.Default.MIBSDir = filepath.Join(echo.Wd(), `data/mibs`)
		err = os.MkdirAll(termConfig.Default.MIBSDir, os.ModePerm)
		if err != nil {
			log.Println(err)
		}
		termConfig.Default.SetDefault()
		termHandler.Register(termConfig.Default.APPRoot, func(path string, h http.Handler) {
			g.Any(path, h)
		})
		g.Route(`GET`, `/group`, GroupIndex)
		g.Route(`GET,POST`, `/group_add`, GroupAdd)
		g.Route(`GET,POST`, `/group_edit`, GroupEdit)
		g.Route(`GET,POST`, `/group_delete`, GroupDelete)
	})
}
<commit_msg>update<commit_after>/*
   Nging is a toolbox for webmasters
   Copyright (C) 2018-present  Wenhui Shen <swh@admpub.com>

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU Affero 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 Affero General Public License for more details.

   You should have received a copy of the GNU Affero General Public License
   along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/

package term

import (
	"fmt"
	"log"
	"net/http"
	"net/url"
	"os"
	"path/filepath"

	"github.com/webx-top/echo"

	"github.com/admpub/nging/application/dbschema"
	"github.com/admpub/nging/application/handler"
	"github.com/admpub/nging/application/library/config"
	"github.com/admpub/nging/application/model"
	termConfig "github.com/admpub/web-terminal/config"
	termHandler "github.com/admpub/web-terminal/handler"
)

type TerminalParam struct {
	Query url.Values
	User  *dbschema.NgingSshUser
}

type key string

var contextKey key = `param`

func init() {
	handler.RegisterToGroup(`/term`, func(g echo.RouteRegister) {
		g.Route(`GET`, `/account`, AccountIndex)
		g.Route(`GET,POST`, `/account_add`, AccountAdd)
		g.Route(`GET,POST`, `/account_edit`, AccountEdit)
		g.Route(`GET,POST`, `/account_delete`, AccountDelete)
		g.Route(`GET`, `/client`, Client)
		g.Route(`GET,POST`, `/sftp`, Sftp)
		termHandler.ParamGet = func(ctx *termHandler.Context, name string) (value string) {
			/*
				defer func() {
					fmt.Println(`web-terminal: [param]`, name, `->`, value)
				}()
			// */
			var (
				param *TerminalParam
				val   interface{}
				ok    bool
			)
			if val, ok = ctx.Data.Load(contextKey); ok {
				param, ok = val.(*TerminalParam)
			}
			if !ok {
				param = &TerminalParam{
					Query: ctx.Request().URL.Query(),
				}

				id := param.Query.Get(`id`)
				if len(id) > 0 {
					m := model.NewSshUser(nil)
					err := m.Get(nil, `id`, id)
					if err == nil {
						param.User = m.NgingSshUser
					}
				}
				ctx.Data.Store(contextKey, param)
			}
			if param.User != nil {
				switch name {
				case `password`:
					return config.DefaultConfig.Decode(param.User.Password)
				case `user`:
					return param.User.Username
				case `protocol`:
					return param.User.Protocol
				case `hostname`:
					return param.User.Host
				case `port`:
					return fmt.Sprint(param.User.Port)
				case `privateKey`:
					return param.User.PrivateKey
				case `passphrase`:
					return config.DefaultConfig.Decode(param.User.Passphrase)
				case `charset`:
					if len(param.User.Charset) == 0 {
						return `UTF-8`
					}
					return param.User.Charset
				}
			}
			value = param.Query.Get(name)
			if name == `password` {
				value = config.DefaultConfig.Decode(value)
			}
			return value
		}
		termConfig.Default.APPRoot = `/client/`
		termConfig.Default.Debug = config.DefaultConfig.Debug
		logDir := filepath.Join(echo.Wd(), `data/logs`)
		err := os.MkdirAll(logDir, os.ModePerm)
		if err != nil {
			log.Println(err)
		}
		termConfig.Default.LogDir = filepath.Join(logDir, `term`)
		termConfig.Default.ResourceDir = `public/xterm`
		termConfig.Default.MIBSDir = filepath.Join(echo.Wd(), `data/mibs`)
		err = os.MkdirAll(termConfig.Default.MIBSDir, os.ModePerm)
		if err != nil {
			log.Println(err)
		}
		termConfig.Default.SetDefault()
		termHandler.Register(termConfig.Default.APPRoot, func(path string, h http.Handler) {
			g.Any(path, h)
		})
		g.Route(`GET`, `/group`, GroupIndex)
		g.Route(`GET,POST`, `/group_add`, GroupAdd)
		g.Route(`GET,POST`, `/group_edit`, GroupEdit)
		g.Route(`GET,POST`, `/group_delete`, GroupDelete)
	})
}
<|endoftext|>


<commit_before>// Copyright 2017 syzkaller project authors. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

// Package git provides helper functions for working with git repositories.
package git

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"net/mail"
	"os"
	"os/exec"
	"regexp"
	"strings"
	"time"

	"github.com/google/syzkaller/pkg/osutil"
)

const (
	DateFormat = "Mon Jan 2 15:04:05 2006 -0700"
	timeout    = time.Hour // timeout for all git invocations
)

// Poll checkouts the specified repository/branch in dir.
// This involves fetching/resetting/cloning as necessary to recover from all possible problems.
// Returns hash of the HEAD commit in the specified branch.
func Poll(dir, repo, branch string) (*Commit, error) {
	runSandboxed(dir, "git", "reset", "--hard")
	origin, err := runSandboxed(dir, "git", "remote", "get-url", "origin")
	if err != nil || strings.TrimSpace(string(origin)) != repo {
		// The repo is here, but it has wrong origin (e.g. repo in config has changed), re-clone.
		if err := clone(dir, repo, branch); err != nil {
			return nil, err
		}
	}
	// Use origin/branch for the case the branch was force-pushed,
	// in such case branch is not the same is origin/branch and we will
	// stuck with the local version forever (git checkout won't fail).
	if _, err := runSandboxed(dir, "git", "checkout", "origin/"+branch); err != nil {
		// No such branch (e.g. branch in config has changed), re-clone.
		if err := clone(dir, repo, branch); err != nil {
			return nil, err
		}
	}
	if _, err := runSandboxed(dir, "git", "fetch", "--no-tags"); err != nil {
		// Something else is wrong, re-clone.
		if err := clone(dir, repo, branch); err != nil {
			return nil, err
		}
	}
	if _, err := runSandboxed(dir, "git", "checkout", "origin/"+branch); err != nil {
		return nil, err
	}
	return HeadCommit(dir)
}

// CheckoutBranch checkouts the specified repository/branch in dir.
// It does not fetch history and efficiently supports checkouts of different repos in the same dir.
func CheckoutBranch(dir, repo, branch string) (*Commit, error) {
	if _, err := runSandboxed(dir, "git", "reset", "--hard"); err != nil {
		if err := initRepo(dir); err != nil {
			return nil, err
		}
	}
	_, err := runSandboxed(dir, "git", "fetch", "--no-tags", "--depth=1", repo, branch)
	if err != nil {
		return nil, err
	}
	if _, err := runSandboxed(dir, "git", "checkout", "FETCH_HEAD"); err != nil {
		return nil, err
	}
	return HeadCommit(dir)
}

// CheckoutCommit checkouts the specified repository on the specified commit in dir.
func CheckoutCommit(dir, repo, commit string) (*Commit, error) {
	if _, err := runSandboxed(dir, "git", "reset", "--hard"); err != nil {
		if err := initRepo(dir); err != nil {
			return nil, err
		}
	}
	_, err := runSandboxed(dir, "git", "fetch", repo)
	if err != nil {
		return nil, err
	}
	if _, err := runSandboxed(dir, "git", "checkout", commit); err != nil {
		return nil, err
	}
	return HeadCommit(dir)
}

func clone(dir, repo, branch string) error {
	if err := initRepo(dir); err != nil {
		return err
	}
	if _, err := runSandboxed(dir, "git", "remote", "add", "origin", repo); err != nil {
		return err
	}
	if _, err := runSandboxed(dir, "git", "fetch", "origin", branch); err != nil {
		return err
	}
	return nil
}

func initRepo(dir string) error {
	if err := os.RemoveAll(dir); err != nil {
		return fmt.Errorf("failed to remove repo dir: %v", err)
	}
	if err := osutil.MkdirAll(dir); err != nil {
		return fmt.Errorf("failed to create repo dir: %v", err)
	}
	if err := osutil.SandboxChown(dir); err != nil {
		return err
	}
	if _, err := runSandboxed(dir, "git", "init"); err != nil {
		return err
	}
	return nil
}

type Commit struct {
	Hash  string
	Title string
	Date  time.Time
}

// HeadCommit returns info about the HEAD commit of the current branch of git repository in dir.
func HeadCommit(dir string) (*Commit, error) {
	output, err := runSandboxed(dir, "git", "log", "--pretty=format:%H%n%s%n%ad", "-n", "1")
	if err != nil {
		return nil, err
	}
	lines := bytes.Split(output, []byte{'\n'})
	if len(lines) != 3 || len(lines[0]) != 40 {
		return nil, fmt.Errorf("unexpected git log output: %q", output)
	}
	date, err := time.Parse(DateFormat, string(lines[2]))
	if err != nil {
		return nil, fmt.Errorf("failed to parse date in git log output: %v\n%q", err, output)
	}
	com := &Commit{
		Hash:  string(lines[0]),
		Title: string(lines[1]),
		Date:  date,
	}
	return com, nil
}

// ListRecentCommits returns list of recent commit titles starting from baseCommit.
func ListRecentCommits(dir, baseCommit string) ([]string, error) {
	// On upstream kernel this produces ~11MB of output.
	// Somewhat inefficient to collect whole output in a slice
	// and then convert to string, but should be bearable.
	output, err := runSandboxed(dir, "git", "log",
		"--pretty=format:%s", "--no-merges", "-n", "200000", baseCommit)
	if err != nil {
		return nil, err
	}
	return strings.Split(string(output), "\n"), nil
}

type FixCommit struct {
	Tag   string
	Title string
}

// ExtractFixTagsFromCommits extracts fixing tags for bugs from git log.
// Given email = "user@domain.com", it searches for tags of the form "user+tag@domain.com"
// and return pairs {tag, commit title}.
func ExtractFixTagsFromCommits(dir, baseCommit, email string) ([]FixCommit, error) {
	since := time.Now().Add(-time.Hour * 24 * 365).Format("01-02-2006")
	cmd := exec.Command("git", "log", "--no-merges", "--since", since, baseCommit)
	cmd.Dir = dir
	stdout, err := cmd.StdoutPipe()
	if err != nil {
		return nil, err
	}
	if err := cmd.Start(); err != nil {
		return nil, err
	}
	defer cmd.Wait()
	defer cmd.Process.Kill()
	return extractFixTags(stdout, email)
}

func extractFixTags(r io.Reader, email string) ([]FixCommit, error) {
	user, domain, err := splitEmail(email)
	if err != nil {
		return nil, fmt.Errorf("failed to parse email %q: %v", email, err)
	}
	var (
		s           = bufio.NewScanner(r)
		commits     []FixCommit
		commitTitle = ""
		commitStart = []byte("commit ")
		bodyPrefix  = []byte("    ")
		userBytes   = []byte(user + "+")
		domainBytes = []byte(domain)
	)
	for s.Scan() {
		ln := s.Bytes()
		if bytes.HasPrefix(ln, commitStart) {
			commitTitle = ""
			continue
		}
		if !bytes.HasPrefix(ln, bodyPrefix) {
			continue
		}
		ln = ln[len(bodyPrefix):]
		if len(ln) == 0 {
			continue
		}
		if commitTitle == "" {
			commitTitle = string(ln)
			continue
		}
		userPos := bytes.Index(ln, userBytes)
		if userPos == -1 {
			continue
		}
		domainPos := bytes.Index(ln[userPos+len(userBytes)+1:], domainBytes)
		if domainPos == -1 {
			continue
		}
		startPos := userPos + len(userBytes)
		endPos := userPos + len(userBytes) + domainPos + 1
		tag := string(ln[startPos:endPos])
		commits = append(commits, FixCommit{tag, commitTitle})
	}
	return commits, s.Err()
}

func splitEmail(email string) (user, domain string, err error) {
	addr, err := mail.ParseAddress(email)
	if err != nil {
		return "", "", err
	}
	at := strings.IndexByte(addr.Address, '@')
	if at == -1 {
		return "", "", fmt.Errorf("no @ in email address")
	}
	user = addr.Address[:at]
	domain = addr.Address[at:]
	if plus := strings.IndexByte(user, '+'); plus != -1 {
		user = user[:plus]
	}
	return
}

// CanonicalizeCommit returns commit title that can be used when checking
// if a particular commit is present in a git tree.
// Some trees add prefixes to commit titles during backporting,
// so we want e.g. commit "foo bar" match "BACKPORT: foo bar".
func CanonicalizeCommit(title string) string {
	for _, prefix := range commitPrefixes {
		if strings.HasPrefix(title, prefix) {
			title = title[len(prefix):]
			break
		}
	}
	return strings.TrimSpace(title)
}

var commitPrefixes = []string{
	"UPSTREAM:",
	"CHROMIUM:",
	"FROMLIST:",
	"BACKPORT:",
	"FROMGIT:",
	"net-backports:",
}

func Patch(dir string, patch []byte) error {
	// Do --dry-run first to not mess with partially consistent state.
	cmd := osutil.Command("patch", "-p1", "--force", "--ignore-whitespace", "--dry-run")
	if err := osutil.Sandbox(cmd, true, true); err != nil {
		return err
	}
	cmd.Stdin = bytes.NewReader(patch)
	cmd.Dir = dir
	if output, err := cmd.CombinedOutput(); err != nil {
		// If it reverses clean, then it's already applied
		// (seems to be the easiest way to detect it).
		cmd = osutil.Command("patch", "-p1", "--force", "--ignore-whitespace", "--reverse", "--dry-run")
		if err := osutil.Sandbox(cmd, true, true); err != nil {
			return err
		}
		cmd.Stdin = bytes.NewReader(patch)
		cmd.Dir = dir
		if _, err := cmd.CombinedOutput(); err == nil {
			return fmt.Errorf("patch is already applied")
		}
		return fmt.Errorf("failed to apply patch:\n%s", output)
	}
	// Now apply for real.
	cmd = osutil.Command("patch", "-p1", "--force", "--ignore-whitespace")
	if err := osutil.Sandbox(cmd, true, true); err != nil {
		return err
	}
	cmd.Stdin = bytes.NewReader(patch)
	cmd.Dir = dir
	if output, err := cmd.CombinedOutput(); err != nil {
		return fmt.Errorf("failed to apply patch after dry run:\n%s", output)
	}
	return nil
}

func runSandboxed(dir, command string, args ...string) ([]byte, error) {
	cmd := osutil.Command(command, args...)
	cmd.Dir = dir
	if err := osutil.Sandbox(cmd, true, false); err != nil {
		return nil, err
	}
	return osutil.Run(timeout, cmd)
}

// CheckRepoAddress does a best-effort approximate check of a git repo address.
func CheckRepoAddress(repo string) bool {
	return gitRepoRe.MatchString(repo)
}

// CheckBranch does a best-effort approximate check of a git branch name.
func CheckBranch(branch string) bool {
	return gitBranchRe.MatchString(branch)
}

func CheckCommitHash(hash string) bool {
	if !gitHashRe.MatchString(hash) {
		return false
	}
	ln := len(hash)
	return ln == 8 || ln == 10 || ln == 12 || ln == 16 || ln == 20 || ln == 40
}

var (
	gitRepoRe   = regexp.MustCompile(`^(git|ssh|http|https|ftp|ftps)://[a-zA-Z0-9-_]+(\.[a-zA-Z0-9-_]+)+(:[0-9]+)?/[a-zA-Z0-9-_./]+\.git(/)?$`)
	gitBranchRe = regexp.MustCompile("^[a-zA-Z0-9-_/.]{2,200}$")
	gitHashRe   = regexp.MustCompile("^[a-f0-9]+$")
)
<commit_msg>pkg/git: don't create shallow repos<commit_after>// Copyright 2017 syzkaller project authors. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

// Package git provides helper functions for working with git repositories.
package git

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"net/mail"
	"os"
	"os/exec"
	"regexp"
	"strings"
	"time"

	"github.com/google/syzkaller/pkg/osutil"
)

const (
	DateFormat = "Mon Jan 2 15:04:05 2006 -0700"
	timeout    = time.Hour // timeout for all git invocations
)

// Poll checkouts the specified repository/branch in dir.
// This involves fetching/resetting/cloning as necessary to recover from all possible problems.
// Returns hash of the HEAD commit in the specified branch.
func Poll(dir, repo, branch string) (*Commit, error) {
	runSandboxed(dir, "git", "reset", "--hard")
	origin, err := runSandboxed(dir, "git", "remote", "get-url", "origin")
	if err != nil || strings.TrimSpace(string(origin)) != repo {
		// The repo is here, but it has wrong origin (e.g. repo in config has changed), re-clone.
		if err := clone(dir, repo, branch); err != nil {
			return nil, err
		}
	}
	// Use origin/branch for the case the branch was force-pushed,
	// in such case branch is not the same is origin/branch and we will
	// stuck with the local version forever (git checkout won't fail).
	if _, err := runSandboxed(dir, "git", "checkout", "origin/"+branch); err != nil {
		// No such branch (e.g. branch in config has changed), re-clone.
		if err := clone(dir, repo, branch); err != nil {
			return nil, err
		}
	}
	if _, err := runSandboxed(dir, "git", "fetch", "--no-tags"); err != nil {
		// Something else is wrong, re-clone.
		if err := clone(dir, repo, branch); err != nil {
			return nil, err
		}
	}
	if _, err := runSandboxed(dir, "git", "checkout", "origin/"+branch); err != nil {
		return nil, err
	}
	return HeadCommit(dir)
}

// CheckoutBranch checkouts the specified repository/branch in dir.
func CheckoutBranch(dir, repo, branch string) (*Commit, error) {
	if _, err := runSandboxed(dir, "git", "reset", "--hard"); err != nil {
		if err := initRepo(dir); err != nil {
			return nil, err
		}
	}
	_, err := runSandboxed(dir, "git", "fetch", repo, branch)
	if err != nil {
		return nil, err
	}
	if _, err := runSandboxed(dir, "git", "checkout", "FETCH_HEAD"); err != nil {
		return nil, err
	}
	return HeadCommit(dir)
}

// CheckoutCommit checkouts the specified repository on the specified commit in dir.
func CheckoutCommit(dir, repo, commit string) (*Commit, error) {
	if _, err := runSandboxed(dir, "git", "reset", "--hard"); err != nil {
		if err := initRepo(dir); err != nil {
			return nil, err
		}
	}
	_, err := runSandboxed(dir, "git", "fetch", repo)
	if err != nil {
		return nil, err
	}
	if _, err := runSandboxed(dir, "git", "checkout", commit); err != nil {
		return nil, err
	}
	return HeadCommit(dir)
}

func clone(dir, repo, branch string) error {
	if err := initRepo(dir); err != nil {
		return err
	}
	if _, err := runSandboxed(dir, "git", "remote", "add", "origin", repo); err != nil {
		return err
	}
	if _, err := runSandboxed(dir, "git", "fetch", "origin", branch); err != nil {
		return err
	}
	return nil
}

func initRepo(dir string) error {
	if err := os.RemoveAll(dir); err != nil {
		return fmt.Errorf("failed to remove repo dir: %v", err)
	}
	if err := osutil.MkdirAll(dir); err != nil {
		return fmt.Errorf("failed to create repo dir: %v", err)
	}
	if err := osutil.SandboxChown(dir); err != nil {
		return err
	}
	if _, err := runSandboxed(dir, "git", "init"); err != nil {
		return err
	}
	return nil
}

type Commit struct {
	Hash  string
	Title string
	Date  time.Time
}

// HeadCommit returns info about the HEAD commit of the current branch of git repository in dir.
func HeadCommit(dir string) (*Commit, error) {
	output, err := runSandboxed(dir, "git", "log", "--pretty=format:%H%n%s%n%ad", "-n", "1")
	if err != nil {
		return nil, err
	}
	lines := bytes.Split(output, []byte{'\n'})
	if len(lines) != 3 || len(lines[0]) != 40 {
		return nil, fmt.Errorf("unexpected git log output: %q", output)
	}
	date, err := time.Parse(DateFormat, string(lines[2]))
	if err != nil {
		return nil, fmt.Errorf("failed to parse date in git log output: %v\n%q", err, output)
	}
	com := &Commit{
		Hash:  string(lines[0]),
		Title: string(lines[1]),
		Date:  date,
	}
	return com, nil
}

// ListRecentCommits returns list of recent commit titles starting from baseCommit.
func ListRecentCommits(dir, baseCommit string) ([]string, error) {
	// On upstream kernel this produces ~11MB of output.
	// Somewhat inefficient to collect whole output in a slice
	// and then convert to string, but should be bearable.
	output, err := runSandboxed(dir, "git", "log",
		"--pretty=format:%s", "--no-merges", "-n", "200000", baseCommit)
	if err != nil {
		return nil, err
	}
	return strings.Split(string(output), "\n"), nil
}

type FixCommit struct {
	Tag   string
	Title string
}

// ExtractFixTagsFromCommits extracts fixing tags for bugs from git log.
// Given email = "user@domain.com", it searches for tags of the form "user+tag@domain.com"
// and return pairs {tag, commit title}.
func ExtractFixTagsFromCommits(dir, baseCommit, email string) ([]FixCommit, error) {
	since := time.Now().Add(-time.Hour * 24 * 365).Format("01-02-2006")
	cmd := exec.Command("git", "log", "--no-merges", "--since", since, baseCommit)
	cmd.Dir = dir
	stdout, err := cmd.StdoutPipe()
	if err != nil {
		return nil, err
	}
	if err := cmd.Start(); err != nil {
		return nil, err
	}
	defer cmd.Wait()
	defer cmd.Process.Kill()
	return extractFixTags(stdout, email)
}

func extractFixTags(r io.Reader, email string) ([]FixCommit, error) {
	user, domain, err := splitEmail(email)
	if err != nil {
		return nil, fmt.Errorf("failed to parse email %q: %v", email, err)
	}
	var (
		s           = bufio.NewScanner(r)
		commits     []FixCommit
		commitTitle = ""
		commitStart = []byte("commit ")
		bodyPrefix  = []byte("    ")
		userBytes   = []byte(user + "+")
		domainBytes = []byte(domain)
	)
	for s.Scan() {
		ln := s.Bytes()
		if bytes.HasPrefix(ln, commitStart) {
			commitTitle = ""
			continue
		}
		if !bytes.HasPrefix(ln, bodyPrefix) {
			continue
		}
		ln = ln[len(bodyPrefix):]
		if len(ln) == 0 {
			continue
		}
		if commitTitle == "" {
			commitTitle = string(ln)
			continue
		}
		userPos := bytes.Index(ln, userBytes)
		if userPos == -1 {
			continue
		}
		domainPos := bytes.Index(ln[userPos+len(userBytes)+1:], domainBytes)
		if domainPos == -1 {
			continue
		}
		startPos := userPos + len(userBytes)
		endPos := userPos + len(userBytes) + domainPos + 1
		tag := string(ln[startPos:endPos])
		commits = append(commits, FixCommit{tag, commitTitle})
	}
	return commits, s.Err()
}

func splitEmail(email string) (user, domain string, err error) {
	addr, err := mail.ParseAddress(email)
	if err != nil {
		return "", "", err
	}
	at := strings.IndexByte(addr.Address, '@')
	if at == -1 {
		return "", "", fmt.Errorf("no @ in email address")
	}
	user = addr.Address[:at]
	domain = addr.Address[at:]
	if plus := strings.IndexByte(user, '+'); plus != -1 {
		user = user[:plus]
	}
	return
}

// CanonicalizeCommit returns commit title that can be used when checking
// if a particular commit is present in a git tree.
// Some trees add prefixes to commit titles during backporting,
// so we want e.g. commit "foo bar" match "BACKPORT: foo bar".
func CanonicalizeCommit(title string) string {
	for _, prefix := range commitPrefixes {
		if strings.HasPrefix(title, prefix) {
			title = title[len(prefix):]
			break
		}
	}
	return strings.TrimSpace(title)
}

var commitPrefixes = []string{
	"UPSTREAM:",
	"CHROMIUM:",
	"FROMLIST:",
	"BACKPORT:",
	"FROMGIT:",
	"net-backports:",
}

func Patch(dir string, patch []byte) error {
	// Do --dry-run first to not mess with partially consistent state.
	cmd := osutil.Command("patch", "-p1", "--force", "--ignore-whitespace", "--dry-run")
	if err := osutil.Sandbox(cmd, true, true); err != nil {
		return err
	}
	cmd.Stdin = bytes.NewReader(patch)
	cmd.Dir = dir
	if output, err := cmd.CombinedOutput(); err != nil {
		// If it reverses clean, then it's already applied
		// (seems to be the easiest way to detect it).
		cmd = osutil.Command("patch", "-p1", "--force", "--ignore-whitespace", "--reverse", "--dry-run")
		if err := osutil.Sandbox(cmd, true, true); err != nil {
			return err
		}
		cmd.Stdin = bytes.NewReader(patch)
		cmd.Dir = dir
		if _, err := cmd.CombinedOutput(); err == nil {
			return fmt.Errorf("patch is already applied")
		}
		return fmt.Errorf("failed to apply patch:\n%s", output)
	}
	// Now apply for real.
	cmd = osutil.Command("patch", "-p1", "--force", "--ignore-whitespace")
	if err := osutil.Sandbox(cmd, true, true); err != nil {
		return err
	}
	cmd.Stdin = bytes.NewReader(patch)
	cmd.Dir = dir
	if output, err := cmd.CombinedOutput(); err != nil {
		return fmt.Errorf("failed to apply patch after dry run:\n%s", output)
	}
	return nil
}

func runSandboxed(dir, command string, args ...string) ([]byte, error) {
	cmd := osutil.Command(command, args...)
	cmd.Dir = dir
	if err := osutil.Sandbox(cmd, true, false); err != nil {
		return nil, err
	}
	return osutil.Run(timeout, cmd)
}

// CheckRepoAddress does a best-effort approximate check of a git repo address.
func CheckRepoAddress(repo string) bool {
	return gitRepoRe.MatchString(repo)
}

// CheckBranch does a best-effort approximate check of a git branch name.
func CheckBranch(branch string) bool {
	return gitBranchRe.MatchString(branch)
}

func CheckCommitHash(hash string) bool {
	if !gitHashRe.MatchString(hash) {
		return false
	}
	ln := len(hash)
	return ln == 8 || ln == 10 || ln == 12 || ln == 16 || ln == 20 || ln == 40
}

var (
	gitRepoRe   = regexp.MustCompile(`^(git|ssh|http|https|ftp|ftps)://[a-zA-Z0-9-_]+(\.[a-zA-Z0-9-_]+)+(:[0-9]+)?/[a-zA-Z0-9-_./]+\.git(/)?$`)
	gitBranchRe = regexp.MustCompile("^[a-zA-Z0-9-_/.]{2,200}$")
	gitHashRe   = regexp.MustCompile("^[a-f0-9]+$")
)
<|endoftext|>


<commit_before>package web

import (
	"net/http"
	"time"

	"github.com/rs/xhandler"
	"golang.org/x/net/context"
)

// NewAPI - New renderer web server API handler.
// Context should have a compiler set with `renderer.NewContext`.
func NewAPI(opts ...Option) http.Handler {
	o := &options{
		reqTimeout: time.Second * 15,
		ctx:        context.Background(),
	}

	for _, opt := range opts {
		opt(o)
	}

	// Create a Chain of middlewares
	var chain xhandler.Chain

	// Add close notifier handler so context is cancelled when the client closes
	// the connection
	chain.UseC(xhandler.CloseHandler)

	// Add timeout handler
	chain.UseC(xhandler.TimeoutHandler(o.reqTimeout))

	// Construct API from middlewares
	if o.reader == nil {
		o.reader = UnmarshalFromRequest()
	}
	chain.UseC(o.reader)
	chain.UseC(CompileFromCtx)
	chain.UseC(RenderFromCtx)

	return chain.HandlerCtx(o.ctx, xhandler.HandlerFuncC(WriteRendered))
}

// Option - Sets web server handler options.
type Option func(*options)

type options struct {
	reqTimeout time.Duration
	ctx        context.Context

	// reader - Component reader that creates context using `renderer.ComponentCtx`.
	reader Middleware

	// templateCtxSetter - Component template context setter middleware.
	// This middleware can read context from request etc.
	// It should set template context using `renderer.WithTemplateCtx`.
	templateCtxSetter Middleware
}

// WithReader - Sets component reader HTTP request middleware.
func WithReader(reader Middleware) Option {
	return func(o *options) {
		o.reader = reader
	}
}

// WithCtxSetter - Sets component template context setter HTTP request middleware.
func WithCtxSetter(templateCtxSetter Middleware) Option {
	return func(o *options) {
		o.templateCtxSetter = templateCtxSetter
	}
}

// WithContext - Sets API server context.
func WithContext(ctx context.Context) Option {
	return func(o *options) {
		o.ctx = ctx
	}
}

// WithTimeout - Sets API server request timeout.
func WithTimeout(t time.Duration) Option {
	return func(o *options) {
		o.reqTimeout = t
	}
}
<commit_msg>web: naming + comments<commit_after>package web

import (
	"net/http"
	"time"

	"github.com/rs/xhandler"
	"golang.org/x/net/context"
)

// NewAPI - New renderer web server API handler.
// Context should have a compiler set with `renderer.NewContext`.
//
// Default options are:
//
// 	WithContext(context.Background()),
// 	WithTimeout(time.Second * 15),
// 	WithComponentSetter(UnmarshalFromRequest()),
//
func NewAPI(opts ...Option) http.Handler {
	o := &options{
		reqTimeout: time.Second * 15,
		ctx:        context.Background(),
	}

	for _, opt := range opts {
		opt(o)
	}

	// Create a Chain of middlewares
	var chain xhandler.Chain

	// Add close notifier handler so context is cancelled when the client closes
	// the connection
	chain.UseC(xhandler.CloseHandler)

	// Add timeout handler
	chain.UseC(xhandler.TimeoutHandler(o.reqTimeout))

	// Construct API from middlewares
	if o.componentSetter == nil {
		o.componentSetter = UnmarshalFromRequest()
	}
	chain.UseC(o.componentSetter)
	chain.UseC(CompileFromCtx)
	chain.UseC(RenderFromCtx)

	return chain.HandlerCtx(o.ctx, xhandler.HandlerFuncC(WriteRendered))
}

// Option - Sets web server handler options.
type Option func(*options)

type options struct {
	reqTimeout time.Duration
	ctx        context.Context

	// componentSetter - Component setter middleware.
	// It should set a component in context using `renderer.ComponentCtx`.
	componentSetter Middleware

	// templateCtxSetter - Component template context setter middleware.
	// This middleware can read context from request etc.
	// It should set template context using `renderer.WithTemplateCtx`.
	templateCtxSetter Middleware
}

// WithComponentSetter - Sets component reader HTTP request middleware.
func WithComponentSetter(componentSetter Middleware) Option {
	return func(o *options) {
		o.componentSetter = componentSetter
	}
}

// WithCtxSetter - Sets component template context setter HTTP request middleware.
func WithCtxSetter(templateCtxSetter Middleware) Option {
	return func(o *options) {
		o.templateCtxSetter = templateCtxSetter
	}
}

// WithContext - Sets API server context.
func WithContext(ctx context.Context) Option {
	return func(o *options) {
		o.ctx = ctx
	}
}

// WithTimeout - Sets API server request timeout.
func WithTimeout(t time.Duration) Option {
	return func(o *options) {
		o.reqTimeout = t
	}
}
<|endoftext|>


<commit_before>package version

import "fmt"

const (
	// VersionMajor is for an API incompatible changes
	VersionMajor = 5
	// VersionMinor is for functionality in a backwards-compatible manner
	VersionMinor = 15
	// VersionPatch is for backwards-compatible bug fixes
	VersionPatch = 0

	// VersionDev indicates development branch. Releases will be empty string.
	VersionDev = ""
)

// Version is the specification version that the package types support.
var Version = fmt.Sprintf("%d.%d.%d%s", VersionMajor, VersionMinor, VersionPatch, VersionDev)
<commit_msg>bump to v5.15.1-dev<commit_after>package version

import "fmt"

const (
	// VersionMajor is for an API incompatible changes
	VersionMajor = 5
	// VersionMinor is for functionality in a backwards-compatible manner
	VersionMinor = 15
	// VersionPatch is for backwards-compatible bug fixes
	VersionPatch = 1

	// VersionDev indicates development branch. Releases will be empty string.
	VersionDev = "-dev"
)

// Version is the specification version that the package types support.
var Version = fmt.Sprintf("%d.%d.%d%s", VersionMajor, VersionMinor, VersionPatch, VersionDev)
<|endoftext|>


<commit_before>package version

import "fmt"

var (
	// Version should be updated by hand at each release
	Version = "0.6.0-dev"

	// GitCommit will be overwritten automatically by the build system
	GitCommit = "HEAD"
)

// FullVersion formats the version to be printed
func FullVersion() string {
	return fmt.Sprintf("%s, build %s", Version, GitCommit)
}
<commit_msg>Bump version to 0.6.0<commit_after>package version

import "fmt"

var (
	// Version should be updated by hand at each release
	Version = "0.6.0"

	// GitCommit will be overwritten automatically by the build system
	GitCommit = "HEAD"
)

// FullVersion formats the version to be printed
func FullVersion() string {
	return fmt.Sprintf("%s, build %s", Version, GitCommit)
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"fmt"
	"os"
	"strings"
	"text/scanner"

	"github.com/NetSys/quilt/stitch"
)

const quiltPath = "QUILT_PATH"

type argOption struct {
	result interface{} // Optionally store result.
}

func usage() {
	fmt.Fprintln(os.Stderr, "Usage: inspect <path to spec file> [commands]\n"+
		"Options\n"+
		" - viz <pdf|ascii>\n"+
		" - check <path to invariants file>\n"+
		" - query [must have check] <path to query file>")
	os.Exit(1)
}

func main() {
	if len(os.Args) < 3 {
		fmt.Println("not enough arguments: ", len(os.Args))
		usage()
	}

	configPath := os.Args[1]

	f, err := os.Open(configPath)
	if err != nil {
		panic(err)
	}
	defer f.Close()

	sc := scanner.Scanner{
		Position: scanner.Position{
			Filename: configPath,
		},
	}
	pathStr, _ := os.LookupEnv(quiltPath)
	pathSlice := strings.Split(pathStr, ":")
	spec, err := stitch.New(*sc.Init(bufio.NewReader(f)), pathSlice)
	if err != nil {
		panic(err)
	}

	containerLabels := make(map[string][]*stitch.Container)
	for _, container := range spec.QueryContainers() {
		labels := container.Labels()
		for _, label := range labels {
			if _, have := containerLabels[label]; !have {
				containerLabels[label] = []*stitch.Container{}
			}
			containerLabels[label] = append(containerLabels[label], container)
		}
	}

	graph := makeGraph()
	for _, conn := range spec.QueryConnections() {
		graph.addConnection(conn.From, conn.To)
	}

	for _, pl := range spec.QueryPlacements() {
		graph.addPlacementRule(pl)
	}

	ignoreNext := 0
	foundFlags := map[string]argOption{}
	func() {
		args := os.Args[2:]
		for i, arg := range args {
			switch {
			case ignoreNext > 0:
				ignoreNext--
			case arg == "viz":
				foundFlags[arg] = argOption{}
				outputFormat := args[i+1] // 'pdf' or 'ascii'
				viz(configPath, spec, graph, outputFormat)
				ignoreNext = 1
			case arg == "check":
				invs, failer, err := check(graph, args[i+1])
				if err != nil && failer == nil {
					fmt.Printf("parsing invariants failed: %s", err)
				} else if err != nil {
					fmt.Println("invariant failed: ", failer.str)
				} else {
					fmt.Println("invariants passed")
				}
				foundFlags[arg] = argOption{result: invs}
				ignoreNext = 1
			case arg == "query":
				foundFlags[arg] = argOption{}

				defer func(i int) {
					if checkOpt, ok := foundFlags["check"]; !ok {
						fmt.Println("query without check")
						usage()
					} else {
						invs := checkOpt.result.([]invariant)
						_, _, err := ask(graph, invs, args[i+1])
						if err != nil {
							fmt.Println(err)
						} else {
							fmt.Println("query passed invariants")
						}
					}
				}(i)
				ignoreNext = 1
			default:
				fmt.Println("unknown arg", arg)
				usage()
			}
		}
	}()
}
<commit_msg>inspect: Print proper number of arguments on error<commit_after>package main

import (
	"bufio"
	"fmt"
	"os"
	"strings"
	"text/scanner"

	"github.com/NetSys/quilt/stitch"
)

const quiltPath = "QUILT_PATH"

type argOption struct {
	result interface{} // Optionally store result.
}

func usage() {
	fmt.Fprintln(os.Stderr, "Usage: inspect <path to spec file> [commands]\n"+
		"Options\n"+
		" - viz <pdf|ascii>\n"+
		" - check <path to invariants file>\n"+
		" - query [must have check] <path to query file>")
	os.Exit(1)
}

func main() {
	if len(os.Args) < 3 {
		fmt.Println("not enough arguments: ", len(os.Args-1))
		usage()
	}

	configPath := os.Args[1]

	f, err := os.Open(configPath)
	if err != nil {
		panic(err)
	}
	defer f.Close()

	sc := scanner.Scanner{
		Position: scanner.Position{
			Filename: configPath,
		},
	}
	pathStr, _ := os.LookupEnv(quiltPath)
	pathSlice := strings.Split(pathStr, ":")
	spec, err := stitch.New(*sc.Init(bufio.NewReader(f)), pathSlice)
	if err != nil {
		panic(err)
	}

	containerLabels := make(map[string][]*stitch.Container)
	for _, container := range spec.QueryContainers() {
		labels := container.Labels()
		for _, label := range labels {
			if _, have := containerLabels[label]; !have {
				containerLabels[label] = []*stitch.Container{}
			}
			containerLabels[label] = append(containerLabels[label], container)
		}
	}

	graph := makeGraph()
	for _, conn := range spec.QueryConnections() {
		graph.addConnection(conn.From, conn.To)
	}

	for _, pl := range spec.QueryPlacements() {
		graph.addPlacementRule(pl)
	}

	ignoreNext := 0
	foundFlags := map[string]argOption{}
	func() {
		args := os.Args[2:]
		for i, arg := range args {
			switch {
			case ignoreNext > 0:
				ignoreNext--
			case arg == "viz":
				foundFlags[arg] = argOption{}
				outputFormat := args[i+1] // 'pdf' or 'ascii'
				viz(configPath, spec, graph, outputFormat)
				ignoreNext = 1
			case arg == "check":
				invs, failer, err := check(graph, args[i+1])
				if err != nil && failer == nil {
					fmt.Printf("parsing invariants failed: %s", err)
				} else if err != nil {
					fmt.Println("invariant failed: ", failer.str)
				} else {
					fmt.Println("invariants passed")
				}
				foundFlags[arg] = argOption{result: invs}
				ignoreNext = 1
			case arg == "query":
				foundFlags[arg] = argOption{}

				defer func(i int) {
					if checkOpt, ok := foundFlags["check"]; !ok {
						fmt.Println("query without check")
						usage()
					} else {
						invs := checkOpt.result.([]invariant)
						_, _, err := ask(graph, invs, args[i+1])
						if err != nil {
							fmt.Println(err)
						} else {
							fmt.Println("query passed invariants")
						}
					}
				}(i)
				ignoreNext = 1
			default:
				fmt.Println("unknown arg", arg)
				usage()
			}
		}
	}()
}
<|endoftext|>


<commit_before>// Package version returns the version of the application
package version

// Version returns the current application version
const Version = "1.0.13"
<commit_msg>bump to v1.0.14<commit_after>// Package version returns the version of the application
package version

// Version returns the current application version
const Version = "1.0.14"
<|endoftext|>


<commit_before>package version

import (
	"fmt"

	"github.com/github/hub/git"
)

var Version = "2.3.0-pre9"

func FullVersion() (string, error) {
	gitVersion, err := git.Version()
	if err != nil {
		gitVersion = "git version (unavailable)"
	}
	return fmt.Sprintf("%s\nhub version %s", gitVersion, Version), err
}
<commit_msg>hub 2.3.0-pre10<commit_after>package version

import (
	"fmt"

	"github.com/github/hub/git"
)

var Version = "2.3.0-pre10"

func FullVersion() (string, error) {
	gitVersion, err := git.Version()
	if err != nil {
		gitVersion = "git version (unavailable)"
	}
	return fmt.Sprintf("%s\nhub version %s", gitVersion, Version), err
}
<|endoftext|>


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

// Package version for fortio holds version information and build information.
package version // import "istio.io/fortio/version"
import (
	"fmt"
	"runtime"

	"istio.io/fortio/log"
)

const (
	major = 0
	minor = 10
	patch = 0

	debug = false // turn on to debug init()
)

var (
	// The following are set by Dockerfile during link time:
	tag       = "n/a"
	buildInfo = "unknown"
	// Number of lines in git status --porcelain; 0 means clean
	gitstatus = "0" // buildInfo default is unknown so no need to add -dirty
	// computed in init()
	version     = ""
	longVersion = ""
)

// Major returns the numerical major version number (first digit of version.Short()).
func Major() int {
	return major
}

// Minor returns the numerical minor version number (second digit of version.Short()).
func Minor() int {
	return minor
}

// Patch returns the numerical patch level (third digit of version.Short()).
func Patch() int {
	return patch
}

// Short returns the 3 digit short version string Major.Minor.Patch[-pre]
// version.Short() is the overall project version (used to version json
// output too). "-pre" is added when the version doesn't match exactly
// a git tag or the build isn't from a clean source tree. (only standard
// dockerfile based build of a clean, tagged source tree should print "X.Y.Z"
// as short version).
func Short() string {
	return version
}

// Long returns the full version and build information.
// Format is "X.Y.X[-pre] YYYY-MM-DD HH:MM SHA[-dirty]" date and time is
// the build date (UTC), sha is the git sha of the source tree.
func Long() string {
	return longVersion
}

// Carefully manually tested all the combinations in pair with Dockerfile
func init() {
	if debug {
		log.SetLogLevel(log.Debug)
	}
	version = fmt.Sprintf("%d.%d.%d", major, minor, patch)
	clean := (gitstatus == "0")
	// The docker build will pass the git tag to the build, if it is clean
	// from a tag it will look like v0.7.0
	if tag != "v"+version || !clean {
		log.Debugf("tag is %v, clean is %v marking as pre release", tag, clean)
		version += "-pre"
	}
	if !clean {
		buildInfo += "-dirty"
		log.Debugf("gitstatus is %q, marking buildinfo as dirty: %v", gitstatus, buildInfo)
	}
	longVersion = version + " " + buildInfo + " " + runtime.Version()
}
<commit_msg>bumb version to 0.10.1 (pre)<commit_after>// Copyright 2017 Istio Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package version for fortio holds version information and build information.
package version // import "istio.io/fortio/version"
import (
	"fmt"
	"runtime"

	"istio.io/fortio/log"
)

const (
	major = 0
	minor = 10
	patch = 1

	debug = false // turn on to debug init()
)

var (
	// The following are set by Dockerfile during link time:
	tag       = "n/a"
	buildInfo = "unknown"
	// Number of lines in git status --porcelain; 0 means clean
	gitstatus = "0" // buildInfo default is unknown so no need to add -dirty
	// computed in init()
	version     = ""
	longVersion = ""
)

// Major returns the numerical major version number (first digit of version.Short()).
func Major() int {
	return major
}

// Minor returns the numerical minor version number (second digit of version.Short()).
func Minor() int {
	return minor
}

// Patch returns the numerical patch level (third digit of version.Short()).
func Patch() int {
	return patch
}

// Short returns the 3 digit short version string Major.Minor.Patch[-pre]
// version.Short() is the overall project version (used to version json
// output too). "-pre" is added when the version doesn't match exactly
// a git tag or the build isn't from a clean source tree. (only standard
// dockerfile based build of a clean, tagged source tree should print "X.Y.Z"
// as short version).
func Short() string {
	return version
}

// Long returns the full version and build information.
// Format is "X.Y.X[-pre] YYYY-MM-DD HH:MM SHA[-dirty]" date and time is
// the build date (UTC), sha is the git sha of the source tree.
func Long() string {
	return longVersion
}

// Carefully manually tested all the combinations in pair with Dockerfile
func init() {
	if debug {
		log.SetLogLevel(log.Debug)
	}
	version = fmt.Sprintf("%d.%d.%d", major, minor, patch)
	clean := (gitstatus == "0")
	// The docker build will pass the git tag to the build, if it is clean
	// from a tag it will look like v0.7.0
	if tag != "v"+version || !clean {
		log.Debugf("tag is %v, clean is %v marking as pre release", tag, clean)
		version += "-pre"
	}
	if !clean {
		buildInfo += "-dirty"
		log.Debugf("gitstatus is %q, marking buildinfo as dirty: %v", gitstatus, buildInfo)
	}
	longVersion = version + " " + buildInfo + " " + runtime.Version()
}
<|endoftext|>


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

package jose

import (
	"encoding/json"
	"fmt"
	"strings"
)

// rawJsonWebSignature represents a raw JWS JSON object. Used for parsing/serializing.
type rawJsonWebSignature struct {
	Payload    *byteBuffer        `json:"payload,omitempty"`
	Signatures []rawSignatureInfo `json:"signatures,omitempty"`
	Protected  *byteBuffer        `json:"protected,omitempty"`
	Header     *rawHeader         `json:"header,omitempty"`
	Signature  *byteBuffer        `json:"signature,omitempty"`
}

// rawSignatureInfo represents a single JWS signature over the JWS payload and protected header.
type rawSignatureInfo struct {
	Protected *byteBuffer `json:"protected,omitempty"`
	Header    *rawHeader  `json:"header,omitempty"`
	Signature *byteBuffer `json:"signature,omitempty"`
}

// JsonWebSignature represents a signed JWS object after parsing.
type JsonWebSignature struct {
	payload    []byte
	Signatures []Signature
}

// Signature represents a single signature over the JWS payload and protected header.
type Signature struct {
	Header    JoseHeader
	Signature []byte
	protected *rawHeader
	header    *rawHeader
	original  *rawSignatureInfo
}

// ParseSigned parses an encrypted message in compact or full serialization format.
func ParseSigned(input string) (*JsonWebSignature, error) {
	input = stripWhitespace(input)
	if strings.HasPrefix(input, "{") {
		return parseSignedFull(input)
	}

	return parseSignedCompact(input)
}

// Get a header value
func (sig Signature) mergedHeaders() rawHeader {
	out := rawHeader{}
	out.merge(sig.protected)
	out.merge(sig.header)
	return out
}

// Compute data to be signed
func (obj JsonWebSignature) computeAuthData(signature *Signature) []byte {
	var serializedProtected string

	if signature.original != nil && signature.original.Protected != nil {
		serializedProtected = signature.original.Protected.base64()
	} else if signature.protected != nil {
		serializedProtected = base64URLEncode(mustSerializeJSON(signature.protected))
	} else {
		serializedProtected = ""
	}

	return []byte(fmt.Sprintf("%s.%s",
		serializedProtected,
		base64URLEncode(obj.payload)))
}

// parseSignedFull parses a message in full format.
func parseSignedFull(input string) (*JsonWebSignature, error) {
	var parsed rawJsonWebSignature
	err := json.Unmarshal([]byte(input), &parsed)
	if err != nil {
		return nil, err
	}

	return parsed.sanitized()
}

// sanitized produces a cleaned-up JWS object from the raw JSON.
func (parsed *rawJsonWebSignature) sanitized() (*JsonWebSignature, error) {
	if parsed.Payload == nil {
		return nil, fmt.Errorf("square/go-jose: missing payload in JWS message")
	}

	obj := &JsonWebSignature{
		payload:    parsed.Payload.bytes(),
		Signatures: make([]Signature, len(parsed.Signatures)),
	}

	if len(parsed.Signatures) == 0 {
		// No signatures array, must be flattened serialization
		signature := Signature{}
		if parsed.Protected != nil && len(parsed.Protected.bytes()) > 0 {
			signature.protected = &rawHeader{}
			err := json.Unmarshal(parsed.Protected.bytes(), signature.protected)
			if err != nil {
				return nil, err
			}
		}

		signature.header = parsed.Header
		signature.Signature = parsed.Signature.bytes()
		// Make a fake "original" rawSignatureInfo to store the unprocessed
		// Protected header. This is necessary because the Protected header can
		// contain arbitrary fields not registered as part of the spec. See
		// https://tools.ietf.org/html/draft-ietf-jose-json-web-signature-41#section-4
		// If we unmarshal Protected into a rawHeader with its explicit list of fields,
		// we cannot marshal losslessly. So we have to keep around the original bytes.
		// This is used in computeAuthData, which will first attempt to use
		// the original bytes of a protected header, and fall back on marshaling the
		// header struct only if those bytes are not available.
		signature.original = &rawSignatureInfo{
			Protected: parsed.Protected,
			Header:    parsed.Header,
			Signature: parsed.Signature,
		}

		signature.Header = signature.mergedHeaders().sanitized()
		obj.Signatures = append(obj.Signatures, signature)
	}

	for i, sig := range parsed.Signatures {
		if sig.Protected != nil && len(sig.Protected.bytes()) > 0 {
			obj.Signatures[i].protected = &rawHeader{}
			err := json.Unmarshal(sig.Protected.bytes(), obj.Signatures[i].protected)
			if err != nil {
				return nil, err
			}
		}

		obj.Signatures[i].Signature = sig.Signature.bytes()

		// Copy value of sig
		original := sig

		obj.Signatures[i].header = sig.Header
		obj.Signatures[i].original = &original
		obj.Signatures[i].Header = obj.Signatures[i].mergedHeaders().sanitized()
	}

	return obj, nil
}

// parseSignedCompact parses a message in compact format.
func parseSignedCompact(input string) (*JsonWebSignature, error) {
	parts := strings.Split(input, ".")
	if len(parts) != 3 {
		return nil, fmt.Errorf("square/go-jose: compact JWS format must have three parts")
	}

	rawProtected, err := base64URLDecode(parts[0])
	if err != nil {
		return nil, err
	}

	payload, err := base64URLDecode(parts[1])
	if err != nil {
		return nil, err
	}

	signature, err := base64URLDecode(parts[2])
	if err != nil {
		return nil, err
	}

	raw := &rawJsonWebSignature{
		Payload:   newBuffer(payload),
		Protected: newBuffer(rawProtected),
		Signature: newBuffer(signature),
	}
	return raw.sanitized()
}

// CompactSerialize serializes an object using the compact serialization format.
func (obj JsonWebSignature) CompactSerialize() (string, error) {
	if len(obj.Signatures) > 1 || obj.Signatures[0].header != nil {
		return "", ErrNotSupported
	}

	serializedProtected := mustSerializeJSON(obj.Signatures[0].protected)

	return fmt.Sprintf(
		"%s.%s.%s",
		base64URLEncode(serializedProtected),
		base64URLEncode(obj.payload),
		base64URLEncode(obj.Signatures[0].Signature)), nil
}

// FullSerialize serializes an object using the full JSON serialization format.
func (obj JsonWebSignature) FullSerialize() string {
	raw := rawJsonWebSignature{
		Payload: newBuffer(obj.payload),
	}

	if len(obj.Signatures) == 1 {
		serializedProtected := mustSerializeJSON(obj.Signatures[0].protected)
		raw.Protected = newBuffer(serializedProtected)
		raw.Header = obj.Signatures[0].header
		raw.Signature = newBuffer(obj.Signatures[0].Signature)
	} else {
		raw.Signatures = make([]rawSignatureInfo, len(obj.Signatures))
		for i, signature := range obj.Signatures {
			serializedProtected := mustSerializeJSON(signature.protected)

			raw.Signatures[i] = rawSignatureInfo{
				Protected: newBuffer(serializedProtected),
				Header:    signature.header,
				Signature: newBuffer(signature.Signature),
			}
		}
	}

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

package jose

import (
	"encoding/json"
	"fmt"
	"strings"
)

// rawJsonWebSignature represents a raw JWS JSON object. Used for parsing/serializing.
type rawJsonWebSignature struct {
	Payload    *byteBuffer        `json:"payload,omitempty"`
	Signatures []rawSignatureInfo `json:"signatures,omitempty"`
	Protected  *byteBuffer        `json:"protected,omitempty"`
	Header     *rawHeader         `json:"header,omitempty"`
	Signature  *byteBuffer        `json:"signature,omitempty"`
}

// rawSignatureInfo represents a single JWS signature over the JWS payload and protected header.
type rawSignatureInfo struct {
	Protected *byteBuffer `json:"protected,omitempty"`
	Header    *rawHeader  `json:"header,omitempty"`
	Signature *byteBuffer `json:"signature,omitempty"`
}

// JsonWebSignature represents a signed JWS object after parsing.
type JsonWebSignature struct {
	payload    []byte
	Signatures []Signature
}

// Signature represents a single signature over the JWS payload and protected header.
type Signature struct {
	// Header fields, such as the signature algorithm
	Header JoseHeader

	// The actual signature value
	Signature []byte

	protected *rawHeader
	header    *rawHeader
	original  *rawSignatureInfo
}

// ParseSigned parses an encrypted message in compact or full serialization format.
func ParseSigned(input string) (*JsonWebSignature, error) {
	input = stripWhitespace(input)
	if strings.HasPrefix(input, "{") {
		return parseSignedFull(input)
	}

	return parseSignedCompact(input)
}

// Get a header value
func (sig Signature) mergedHeaders() rawHeader {
	out := rawHeader{}
	out.merge(sig.protected)
	out.merge(sig.header)
	return out
}

// Compute data to be signed
func (obj JsonWebSignature) computeAuthData(signature *Signature) []byte {
	var serializedProtected string

	if signature.original != nil && signature.original.Protected != nil {
		serializedProtected = signature.original.Protected.base64()
	} else if signature.protected != nil {
		serializedProtected = base64URLEncode(mustSerializeJSON(signature.protected))
	} else {
		serializedProtected = ""
	}

	return []byte(fmt.Sprintf("%s.%s",
		serializedProtected,
		base64URLEncode(obj.payload)))
}

// parseSignedFull parses a message in full format.
func parseSignedFull(input string) (*JsonWebSignature, error) {
	var parsed rawJsonWebSignature
	err := json.Unmarshal([]byte(input), &parsed)
	if err != nil {
		return nil, err
	}

	return parsed.sanitized()
}

// sanitized produces a cleaned-up JWS object from the raw JSON.
func (parsed *rawJsonWebSignature) sanitized() (*JsonWebSignature, error) {
	if parsed.Payload == nil {
		return nil, fmt.Errorf("square/go-jose: missing payload in JWS message")
	}

	obj := &JsonWebSignature{
		payload:    parsed.Payload.bytes(),
		Signatures: make([]Signature, len(parsed.Signatures)),
	}

	if len(parsed.Signatures) == 0 {
		// No signatures array, must be flattened serialization
		signature := Signature{}
		if parsed.Protected != nil && len(parsed.Protected.bytes()) > 0 {
			signature.protected = &rawHeader{}
			err := json.Unmarshal(parsed.Protected.bytes(), signature.protected)
			if err != nil {
				return nil, err
			}
		}

		signature.header = parsed.Header
		signature.Signature = parsed.Signature.bytes()
		// Make a fake "original" rawSignatureInfo to store the unprocessed
		// Protected header. This is necessary because the Protected header can
		// contain arbitrary fields not registered as part of the spec. See
		// https://tools.ietf.org/html/draft-ietf-jose-json-web-signature-41#section-4
		// If we unmarshal Protected into a rawHeader with its explicit list of fields,
		// we cannot marshal losslessly. So we have to keep around the original bytes.
		// This is used in computeAuthData, which will first attempt to use
		// the original bytes of a protected header, and fall back on marshaling the
		// header struct only if those bytes are not available.
		signature.original = &rawSignatureInfo{
			Protected: parsed.Protected,
			Header:    parsed.Header,
			Signature: parsed.Signature,
		}

		signature.Header = signature.mergedHeaders().sanitized()
		obj.Signatures = append(obj.Signatures, signature)
	}

	for i, sig := range parsed.Signatures {
		if sig.Protected != nil && len(sig.Protected.bytes()) > 0 {
			obj.Signatures[i].protected = &rawHeader{}
			err := json.Unmarshal(sig.Protected.bytes(), obj.Signatures[i].protected)
			if err != nil {
				return nil, err
			}
		}

		obj.Signatures[i].Signature = sig.Signature.bytes()

		// Copy value of sig
		original := sig

		obj.Signatures[i].header = sig.Header
		obj.Signatures[i].original = &original
		obj.Signatures[i].Header = obj.Signatures[i].mergedHeaders().sanitized()
	}

	return obj, nil
}

// parseSignedCompact parses a message in compact format.
func parseSignedCompact(input string) (*JsonWebSignature, error) {
	parts := strings.Split(input, ".")
	if len(parts) != 3 {
		return nil, fmt.Errorf("square/go-jose: compact JWS format must have three parts")
	}

	rawProtected, err := base64URLDecode(parts[0])
	if err != nil {
		return nil, err
	}

	payload, err := base64URLDecode(parts[1])
	if err != nil {
		return nil, err
	}

	signature, err := base64URLDecode(parts[2])
	if err != nil {
		return nil, err
	}

	raw := &rawJsonWebSignature{
		Payload:   newBuffer(payload),
		Protected: newBuffer(rawProtected),
		Signature: newBuffer(signature),
	}
	return raw.sanitized()
}

// CompactSerialize serializes an object using the compact serialization format.
func (obj JsonWebSignature) CompactSerialize() (string, error) {
	if len(obj.Signatures) > 1 || obj.Signatures[0].header != nil {
		return "", ErrNotSupported
	}

	serializedProtected := mustSerializeJSON(obj.Signatures[0].protected)

	return fmt.Sprintf(
		"%s.%s.%s",
		base64URLEncode(serializedProtected),
		base64URLEncode(obj.payload),
		base64URLEncode(obj.Signatures[0].Signature)), nil
}

// FullSerialize serializes an object using the full JSON serialization format.
func (obj JsonWebSignature) FullSerialize() string {
	raw := rawJsonWebSignature{
		Payload: newBuffer(obj.payload),
	}

	if len(obj.Signatures) == 1 {
		serializedProtected := mustSerializeJSON(obj.Signatures[0].protected)
		raw.Protected = newBuffer(serializedProtected)
		raw.Header = obj.Signatures[0].header
		raw.Signature = newBuffer(obj.Signatures[0].Signature)
	} else {
		raw.Signatures = make([]rawSignatureInfo, len(obj.Signatures))
		for i, signature := range obj.Signatures {
			serializedProtected := mustSerializeJSON(signature.protected)

			raw.Signatures[i] = rawSignatureInfo{
				Protected: newBuffer(serializedProtected),
				Header:    signature.header,
				Signature: newBuffer(signature.Signature),
			}
		}
	}

	return string(mustSerializeJSON(raw))
}
<|endoftext|>


<commit_before>package version

var (
	Version = "1.0.1"

	// Build will be overwritten automatically by the build system
	Build = "-dev"

	// GitCommit will be overwritten automatically by the build system
	GitCommit = "HEAD"
)

func FullVersion() string {
	return Version + Build + " (" + GitCommit + ")"
}
<commit_msg>bump version to 1.0.2<commit_after>package version

var (
	Version = "1.0.2"

	// Build will be overwritten automatically by the build system
	Build = "-dev"

	// GitCommit will be overwritten automatically by the build system
	GitCommit = "HEAD"
)

func FullVersion() string {
	return Version + Build + " (" + GitCommit + ")"
}
<|endoftext|>


<commit_before>package version

import "fmt"

const (
	// VersionMajor is for an API incompatible changes
	VersionMajor = 4
	// VersionMinor is for functionality in a backwards-compatible manner
	VersionMinor = 0
	// VersionPatch is for backwards-compatible bug fixes
	VersionPatch = 0

	// VersionDev indicates development branch. Releases will be empty string.
	VersionDev = ""
)

// Version is the specification version that the package types support.
var Version = fmt.Sprintf("%d.%d.%d%s", VersionMajor, VersionMinor, VersionPatch, VersionDev)
<commit_msg>bump o v4.0.1-dev<commit_after>package version

import "fmt"

const (
	// VersionMajor is for an API incompatible changes
	VersionMajor = 4
	// VersionMinor is for functionality in a backwards-compatible manner
	VersionMinor = 0
	// VersionPatch is for backwards-compatible bug fixes
	VersionPatch = 1

	// VersionDev indicates development branch. Releases will be empty string.
	VersionDev = "-dev"
)

// Version is the specification version that the package types support.
var Version = fmt.Sprintf("%d.%d.%d%s", VersionMajor, VersionMinor, VersionPatch, VersionDev)
<|endoftext|>


<commit_before>package version

import "fmt"

const (
	// VersionMajor is for an API incompatible changes
	VersionMajor = 4
	// VersionMinor is for functionality in a backwards-compatible manner
	VersionMinor = 0
	// VersionPatch is for backwards-compatible bug fixes
	VersionPatch = 1

	// VersionDev indicates development branch. Releases will be empty string.
	VersionDev = ""
)

// Version is the specification version that the package types support.
var Version = fmt.Sprintf("%d.%d.%d%s", VersionMajor, VersionMinor, VersionPatch, VersionDev)
<commit_msg>Bump to v4.0.2-dev<commit_after>package version

import "fmt"

const (
	// VersionMajor is for an API incompatible changes
	VersionMajor = 4
	// VersionMinor is for functionality in a backwards-compatible manner
	VersionMinor = 0
	// VersionPatch is for backwards-compatible bug fixes
	VersionPatch = 2

	// VersionDev indicates development branch. Releases will be empty string.
	VersionDev = "-dev"
)

// Version is the specification version that the package types support.
var Version = fmt.Sprintf("%d.%d.%d%s", VersionMajor, VersionMinor, VersionPatch, VersionDev)
<|endoftext|>