<commit_before>package bob_test

import (
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/rafecolton/bob"
	"testing"
)

import (
	"github.com/rafecolton/bob/parser"
)

import (
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"sort"
)

func TestBuilder(t *testing.T) {
	RegisterFailHandler(Fail)
	RunSpecs(t, "Builder Specs")
}

var _ = Describe("Setup", func() {
	var (
		branch          string
		rev             string
		short           string
		top             string
		expectedFiles   []string
		subject         *Builder
		baseSubSequence = &parser.SubSequence{
			Metadata: &parser.SubSequenceMetadata{
				Name:       "base",
				Dockerfile: "Dockerfile.base",
				Excluded:   []string{"spec", "tmp"},
				Included:   []string{"Gemfile", "Gemfile.lock"},
			},
			SubCommand: []exec.Cmd{
				*&exec.Cmd{
					Path: "docker",
					Args: []string{
						"docker",
						"build",
						"-t",
						"quay.io/modcloth/style-gallery:035c4ea0-d73b-5bde-7d6f-c806b04f2ec3",
						"--rm",
						"--no-cache",
						".",
					},
				},
				*&exec.Cmd{
					Path: "docker",
					Args: []string{"docker", "tag", "<IMG>", "quay.io/modcloth/style-gallery:base"},
				},
			},
		}
		appSubSequence = &parser.SubSequence{
			Metadata: &parser.SubSequenceMetadata{
				Name:       "app",
				Dockerfile: "Dockerfile",
				Excluded:   []string{"spec", "tmp"},
				Included:   []string{},
			},
			SubCommand: []exec.Cmd{
				*&exec.Cmd{
					Path: "docker",
					Args: []string{
						"docker",
						"build",
						"-t",
						"quay.io/modcloth/style-gallery:035c4ea0-d73b-5bde-7d6f-c806b04f2ec3",
						"--rm",
						"--no-cache",
						".",
					},
				},
				*&exec.Cmd{
					Path: "docker",
					Args: []string{
						"docker",
						"tag",
						"<IMG>",
						fmt.Sprintf("quay.io/modcloth/style-gallery:%s", branch),
					},
				},
				*&exec.Cmd{
					Path: "docker",
					Args: []string{
						"docker",
						"tag",
						"<IMG>",
						fmt.Sprintf("quay.io/modcloth/style-gallery:%s", rev),
					},
				},
				*&exec.Cmd{
					Path: "docker",
					Args: []string{
						"docker",
						"tag",
						"<IMG>",
						fmt.Sprintf("quay.io/modcloth/style-gallery:%s", short),
					},
				},
				*&exec.Cmd{
					Path: "docker",
					Args: []string{"docker", "push", "quay.io/modcloth/style-gallery"},
				},
			},
		}
	)

	BeforeEach(func() {
		subject = NewBuilder(nil, false)
		top = os.Getenv("PWD")
		git, _ := exec.LookPath("git")
		// branch
		branchCmd := &exec.Cmd{
			Path: git,
			Dir:  top,
			Args: []string{git, "rev-parse", "-q", "--abbrev-ref", "HEAD"},
		}

		branchBytes, _ := branchCmd.Output()
		branch = string(branchBytes)[:len(branchBytes)-1]

		// rev
		revCmd := &exec.Cmd{
			Path: git,
			Dir:  top,
			Args: []string{git, "rev-parse", "-q", "HEAD"},
		}
		revBytes, _ := revCmd.Output()
		rev = string(revBytes)[:len(revBytes)-1]

		// short
		shortCmd := &exec.Cmd{
			Path: git,
			Dir:  top,
			Args: []string{git, "describe", "--always"},
		}
		shortBytes, _ := shortCmd.Output()
		short = string(shortBytes)[:len(shortBytes)-1]
	})

	AfterEach(func() {
		subject.CleanWorkdir()
	})

	Context("with the base container sequence", func() {
		It("places the correct files in the workdir", func() {
			subject.SetNextSubSequence(baseSubSequence)
			subject.CleanWorkdir()
			subject.Setup()

			expectedFiles = []string{
				"Dockerfile",
				"Gemfile",
				"Gemfile.lock",
				"README.txt",
			}

			files, _ := ioutil.ReadDir(subject.Workdir())
			fileNames := []string{}
			for _, v := range files {
				fileNames = append(fileNames, v.Name())
			}

			sort.Strings(fileNames)
			sort.Strings(expectedFiles)

			Expect(fileNames).To(Equal(expectedFiles))
		})
	})

	Context("with the app container sequence", func() {
		It("places the correct files in the workdir", func() {
			subject.SetNextSubSequence(appSubSequence)
			subject.CleanWorkdir()
			subject.Setup()

			expectedFiles = []string{
				"Dockerfile",
				"Dockerfile.base",
				"Gemfile",
				"Gemfile.lock",
				"foo",
				"README.txt",
				"other_file.txt",
			}

			files, _ := ioutil.ReadDir(subject.Workdir())
			fileNames := []string{}
			for _, v := range files {
				fileNames = append(fileNames, v.Name())
			}

			sort.Strings(fileNames)
			sort.Strings(expectedFiles)

			Expect(fileNames).To(Equal(expectedFiles))
		})
	})
})
<commit_msg>Cleaning up the bob_test slightly<commit_after>package bob_test

import (
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/rafecolton/bob"
	"testing"
)

import (
	"github.com/rafecolton/bob/parser"
)

import (
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"sort"
)

func TestBuilder(t *testing.T) {
	RegisterFailHandler(Fail)
	RunSpecs(t, "Builder Specs")
}

var _ = Describe("Setup", func() {
	var (
		branch          string
		rev             string
		short           string
		top             string
		subject         *Builder
		baseSubSequence = &parser.SubSequence{
			Metadata: &parser.SubSequenceMetadata{
				Name:       "base",
				Dockerfile: "Dockerfile.base",
				Excluded:   []string{"spec", "tmp"},
				Included:   []string{"Gemfile", "Gemfile.lock"},
			},
			SubCommand: []exec.Cmd{
				*&exec.Cmd{
					Path: "docker",
					Args: []string{
						"docker",
						"build",
						"-t",
						"quay.io/modcloth/style-gallery:035c4ea0-d73b-5bde-7d6f-c806b04f2ec3",
						"--rm",
						"--no-cache",
						".",
					},
				},
				*&exec.Cmd{
					Path: "docker",
					Args: []string{"docker", "tag", "<IMG>", "quay.io/modcloth/style-gallery:base"},
				},
			},
		}
		appSubSequence = &parser.SubSequence{
			Metadata: &parser.SubSequenceMetadata{
				Name:       "app",
				Dockerfile: "Dockerfile",
				Excluded:   []string{"spec", "tmp"},
				Included:   []string{},
			},
			SubCommand: []exec.Cmd{
				*&exec.Cmd{
					Path: "docker",
					Args: []string{
						"docker",
						"build",
						"-t",
						"quay.io/modcloth/style-gallery:035c4ea0-d73b-5bde-7d6f-c806b04f2ec3",
						"--rm",
						"--no-cache",
						".",
					},
				},
				*&exec.Cmd{
					Path: "docker",
					Args: []string{
						"docker",
						"tag",
						"<IMG>",
						fmt.Sprintf("quay.io/modcloth/style-gallery:%s", branch),
					},
				},
				*&exec.Cmd{
					Path: "docker",
					Args: []string{
						"docker",
						"tag",
						"<IMG>",
						fmt.Sprintf("quay.io/modcloth/style-gallery:%s", rev),
					},
				},
				*&exec.Cmd{
					Path: "docker",
					Args: []string{
						"docker",
						"tag",
						"<IMG>",
						fmt.Sprintf("quay.io/modcloth/style-gallery:%s", short),
					},
				},
				*&exec.Cmd{
					Path: "docker",
					Args: []string{"docker", "push", "quay.io/modcloth/style-gallery"},
				},
			},
		}
	)

	BeforeEach(func() {
		subject = NewBuilder(nil, false)
		top = os.Getenv("PWD")
		git, _ := exec.LookPath("git")
		// branch
		branchCmd := &exec.Cmd{
			Path: git,
			Dir:  top,
			Args: []string{git, "rev-parse", "-q", "--abbrev-ref", "HEAD"},
		}

		branchBytes, _ := branchCmd.Output()
		branch = string(branchBytes)[:len(branchBytes)-1]

		// rev
		revCmd := &exec.Cmd{
			Path: git,
			Dir:  top,
			Args: []string{git, "rev-parse", "-q", "HEAD"},
		}
		revBytes, _ := revCmd.Output()
		rev = string(revBytes)[:len(revBytes)-1]

		// short
		shortCmd := &exec.Cmd{
			Path: git,
			Dir:  top,
			Args: []string{git, "describe", "--always"},
		}
		shortBytes, _ := shortCmd.Output()
		short = string(shortBytes)[:len(shortBytes)-1]
	})

	Context("with the base container sequence", func() {
		It("places the correct files in the workdir", func() {
			subject.SetNextSubSequence(baseSubSequence)
			subject.CleanWorkdir()
			subject.Setup()

			expectedFiles := []string{
				"Dockerfile",
				"Gemfile",
				"Gemfile.lock",
			}

			files, _ := ioutil.ReadDir(subject.Workdir())
			fileNames := make([]string, len(files), len(files))

			for i, v := range files {
				fileNames[i] = v.Name()
			}

			sort.Strings(fileNames)
			sort.Strings(expectedFiles)
			Expect(fileNames).To(Equal(expectedFiles))
		})
	})

	Context("with the app container sequence", func() {
		It("places the correct files in the workdir", func() {
			subject.SetNextSubSequence(appSubSequence)
			subject.CleanWorkdir()
			subject.Setup()

			expectedFiles := []string{
				"Dockerfile",
				"Dockerfile.base",
				"Gemfile",
				"Gemfile.lock",
				"foo",
				"README.txt",
				"other_file.txt",
			}

			files, _ := ioutil.ReadDir(subject.Workdir())
			fileNames := make([]string, len(files), len(files))
			for i, v := range files {
				fileNames[i] = v.Name()
			}

			sort.Strings(fileNames)
			sort.Strings(expectedFiles)

			Expect(fileNames).To(Equal(expectedFiles))
		})
	})
})
<|endoftext|>


<commit_before>package main

/*
Given a version number MAJOR.MINOR.PATCH, increment the:

MAJOR version when you make incompatible API changes,
MINOR version when you add functionality in a backwards-compatible manner, and
PATCH version when you make backwards-compatible bug fixes.
*/
const VersionMajor = 4
const VersionMinor = 15
const VersionPatch = 4
<commit_msg>Version Bump<commit_after>package main

/*
Given a version number MAJOR.MINOR.PATCH, increment the:

MAJOR version when you make incompatible API changes,
MINOR version when you add functionality in a backwards-compatible manner, and
PATCH version when you make backwards-compatible bug fixes.
*/
const VersionMajor = 4
const VersionMinor = 15
const VersionPatch = 5
<|endoftext|>


<commit_before>package gf

const VERSION  = "v1.3.8"
const AUTHORS  = "john<john@johng.cn>"

<commit_msg>VERSION updates<commit_after>package gf

const VERSION  = "v1.4.0"
const AUTHORS  = "john<john@johng.cn>"

<|endoftext|>


<commit_before>package main

// The git commit that was compiled. This will be filled in by the compiler.
var (
	GitCommit   string
	GitDescribe string
)

// The main version number that is being run at the moment.
const Version = "0.6.2"

// A pre-release marker for the version. If this is "" (empty string)
// then it means that it is a final release. Otherwise, this is a pre-release
// such as "dev" (in development), "beta", "rc1", etc.
const VersionPrerelease = ""
<commit_msg>Bumps version up to 0.6.3.<commit_after>package main

// The git commit that was compiled. This will be filled in by the compiler.
var (
	GitCommit   string
	GitDescribe string
)

// The main version number that is being run at the moment.
const Version = "0.6.3"

// A pre-release marker for the version. If this is "" (empty string)
// then it means that it is a final release. Otherwise, this is a pre-release
// such as "dev" (in development), "beta", "rc1", etc.
const VersionPrerelease = ""
<|endoftext|>


<commit_before>package main

const version string = "1.9.1"
<commit_msg>Bump version number to 1.10.0<commit_after>package main

const version string = "1.10.0"
<|endoftext|>


<commit_before>package main

const Name string = "aurl"
const Version string = "1.0.1"
const Author string = "Daisuke Miyamoto <miyamoto.daisuke@classmethod.jp>"
<commit_msg>prepare for next development iteration<commit_after>package main

const Name string = "aurl"
const Version string = "1.1.0-SNAPSHOT"
const Author string = "Daisuke Miyamoto <miyamoto.daisuke@classmethod.jp>"
<|endoftext|>


<commit_before>package trdsql

// Version is trdsql version
var Version = `v0.7.3`
<commit_msg>bump version<commit_after>package trdsql

// Version is trdsql version
var Version = `v0.7.4`
<|endoftext|>


<commit_before>package bimg

const Version = "0.1.21"
<commit_msg>feat(version): bump<commit_after>package bimg

const Version = "0.1.22"
<|endoftext|>


<commit_before>package httpfile

import (
	"bufio"
	"fmt"
	"io"
	"io/ioutil"
	"math"
	"net"
	"net/http"
	"net/url"
	"os"
	"sync"
	"time"

	"github.com/go-errors/errors"
	"github.com/itchio/httpkit/retrycontext"
	uuid "github.com/satori/go.uuid"
)

// A GetURLFunc returns a URL we can download the resource from.
// It's handy to have this as a function rather than a constant for signed expiring URLs
type GetURLFunc func() (urlString string, err error)

// A NeedsRenewalFunc analyzes an HTTP response and returns true if it needs to be renewed
type NeedsRenewalFunc func(res *http.Response, body []byte) bool

// A LogFunc prints debug message
type LogFunc func(msg string)

// amount we're willing to download and throw away
const maxDiscard int64 = 1 * 1024 * 1024 // 1MB

var ErrNotFound = errors.New("HTTP file not found on server")

type HTTPFile struct {
	getURL        GetURLFunc
	needsRenewal  NeedsRenewalFunc
	client        *http.Client
	retrySettings *retrycontext.Settings

	Log LogFunc

	name   string
	size   int64
	offset int64 // for io.ReadSeeker

	ReaderStaleThreshold time.Duration

	closed bool

	readers      map[string]*httpReader
	readersMutex sync.Mutex

	currentURL string
	urlMutex   sync.Mutex
}

type httpReader struct {
	file      *HTTPFile
	id        string
	touchedAt time.Time
	offset    int64
	body      io.ReadCloser
	reader    *bufio.Reader
}

const DefaultReaderStaleThreshold = time.Second * time.Duration(10)

func (hr *httpReader) Stale() bool {
	return time.Since(hr.touchedAt) > hr.file.ReaderStaleThreshold
}

func (hr *httpReader) Read(data []byte) (int, error) {
	hr.touchedAt = time.Now()
	readBytes, err := hr.reader.Read(data)
	hr.offset += int64(readBytes)

	if err != nil {
		return readBytes, err
	}
	return readBytes, nil
}

func (hr *httpReader) Discard(n int) (int, error) {
	hr.touchedAt = time.Now()
	discarded, err := hr.reader.Discard(n)
	hr.offset += int64(discarded)

	if err != nil {
		return discarded, err
	}
	return discarded, nil
}

func (hr *httpReader) Connect() error {
	if hr.body != nil {
		err := hr.body.Close()
		if err != nil {
			return err
		}

		hr.body = nil
		hr.reader = nil
	}

	tryUrl := func(urlStr string) (bool, error) {
		req, err := http.NewRequest("GET", urlStr, nil)
		if err != nil {
			return false, err
		}

		byteRange := fmt.Sprintf("bytes=%d-", hr.offset)
		req.Header.Set("Range", byteRange)

		res, err := hr.file.client.Do(req)
		if err != nil {
			return false, err
		}
		hr.file.log("did request, status %d", res.StatusCode)

		if res.StatusCode == 200 && hr.offset > 0 {
			defer res.Body.Close()

			err = fmt.Errorf("HTTP Range header not supported by %s, bailing out", req.Host)
			return false, err
		}

		if res.StatusCode/100 != 2 {
			defer res.Body.Close()

			body, err := ioutil.ReadAll(res.Body)
			if err != nil {
				body = []byte("could not read error body")
				err = nil
			}

			if hr.file.needsRenewal(res, body) {
				return true, nil
			}

			err = fmt.Errorf("HTTP %d returned by %s (%s), bailing out", res.StatusCode, req.Host, string(body))
			return false, err
		}

		hr.reader = bufio.NewReaderSize(res.Body, int(maxDiscard))
		hr.body = res.Body
		return false, nil
	}

	urlStr := hr.file.getCurrentURL()
	shouldRenew, err := tryUrl(urlStr)
	if err != nil {
		return err
	}

	if shouldRenew {
		urlStr, err = hr.file.renewURL()
		if err != nil {
			return err
		}

		shouldRenew, err = tryUrl(urlStr)
		if err != nil {
			return err
		}

		if shouldRenew {
			return fmt.Errorf("getting expired URLs from URL source (timezone issue?)")
		}
	}

	return nil
}

func (hr *httpReader) Close() error {
	err := hr.body.Close()

	if err != nil {
		return err
	}
	return nil
}

var _ io.Seeker = (*HTTPFile)(nil)
var _ io.Reader = (*HTTPFile)(nil)
var _ io.ReaderAt = (*HTTPFile)(nil)
var _ io.Closer = (*HTTPFile)(nil)

type Settings struct {
	Client        *http.Client
	RetrySettings *retrycontext.Settings
}

func New(getURL GetURLFunc, needsRenewal NeedsRenewalFunc, settings *Settings) (*HTTPFile, error) {
	client := settings.Client
	if client == nil {
		client = http.DefaultClient
	}

	retryCtx := retrycontext.NewDefault()
	if settings.RetrySettings != nil {
		retryCtx.Settings = *settings.RetrySettings
	}

	for retryCtx.ShouldTry() {
		urlStr, err := getURL()
		if err != nil {
			// this assumes getURL does its own retrying
			return nil, err
		}

		parsedUrl, err := url.Parse(urlStr)
		if err != nil {
			// can't recover from a bad url
			return nil, err
		}

		req, err := http.NewRequest("HEAD", urlStr, nil)
		if err != nil {
			// internal error
			return nil, err
		}

		res, err := client.Do(req)
		if err != nil {
			// we can recover from some client errors
			// (example: temporarily offline, DNS failure, etc.)
			retryCtx.Retry(err.Error())
			continue
		}

		if res.StatusCode != 200 {
			if res.StatusCode == 404 {
				// no need to retry - it's not coming back
				return nil, errors.Wrap(ErrNotFound, 1)
			}

			body, _ := ioutil.ReadAll(res.Body)
			if needsRenewal(res, body) {
				retryCtx.Retry(fmt.Sprintf("HTTP %d (needs renewal)", res.StatusCode))
				continue
			}

			if res.StatusCode == 429 || res.StatusCode/100 == 5 {
				retryCtx.Retry(fmt.Sprintf("HTTP %d (retrying)", res.StatusCode))
				continue
			}

			return nil, fmt.Errorf("Expected HTTP 200, got HTTP %d, not retrying", res.StatusCode)
		}

		hf := &HTTPFile{
			currentURL:    urlStr,
			getURL:        getURL,
			retrySettings: &retryCtx.Settings,
			needsRenewal:  needsRenewal,
			client:        client,

			name:    parsedUrl.Path,
			size:    res.ContentLength,
			readers: make(map[string]*httpReader),

			ReaderStaleThreshold: DefaultReaderStaleThreshold,
		}
		return hf, nil
	}

	return nil, fmt.Errorf("Could not access remote file. Last error: %s", retryCtx.LastMessage)
}

func (hf *HTTPFile) NumReaders() int {
	return len(hf.readers)
}

func (hf *HTTPFile) borrowReader(offset int64) (*httpReader, error) {
	hf.readersMutex.Lock()
	defer hf.readersMutex.Unlock()

	var bestReader string
	var bestDiff int64 = math.MaxInt64

	for _, reader := range hf.readers {
		if reader.Stale() {
			delete(hf.readers, reader.id)

			err := reader.Close()
			if err != nil {
				return nil, err
			}
			continue
		}

		diff := offset - reader.offset
		if diff >= 0 && diff < maxDiscard {
			if diff < bestDiff {
				bestReader = reader.id
				bestDiff = diff
			}
		}
	}

	if bestReader != "" {
		// re-use!
		reader := hf.readers[bestReader]
		delete(hf.readers, bestReader)

		// discard if needed
		if bestDiff > 0 {
			hf.log("borrow: for %d, re-using %d by discarding %d bytes", offset, reader.offset, bestDiff)

			// XXX: not int64-clean
			_, err := reader.Discard(int(bestDiff))
			if err != nil {
				if shouldRetry(err) {
					hf.log("borrow: for %d, discard failed because of retriable error, reconnecting", offset)
					reader.offset = offset
					err = reader.Connect()
					if err != nil {
						return nil, err
					}
				} else {
					return nil, err
				}
			}
		}

		return reader, nil
	}

	// provision a new reader
	hf.log("borrow: making fresh for offset %d", offset)

	reader := &httpReader{
		file:      hf,
		id:        uuid.NewV4().String(),
		touchedAt: time.Now(),
		offset:    offset,
	}

	err := reader.Connect()
	if err != nil {
		return nil, err
	}

	return reader, nil
}

func (hf *HTTPFile) returnReader(reader *httpReader) {
	hf.readersMutex.Lock()
	defer hf.readersMutex.Unlock()

	// TODO: enforce max idle readers ?

	reader.touchedAt = time.Now()
	hf.readers[reader.id] = reader
}

func (hf *HTTPFile) getCurrentURL() string {
	hf.urlMutex.Lock()
	defer hf.urlMutex.Unlock()

	return hf.currentURL
}

func (hf *HTTPFile) renewURL() (string, error) {
	hf.urlMutex.Lock()
	defer hf.urlMutex.Unlock()

	urlStr, err := hf.getURL()
	if err != nil {
		return "", err
	}

	hf.currentURL = urlStr
	return hf.currentURL, nil
}

func (hf *HTTPFile) Stat() (os.FileInfo, error) {
	return &httpFileInfo{hf}, nil
}

func (hf *HTTPFile) Seek(offset int64, whence int) (int64, error) {
	var newOffset int64

	switch whence {
	case os.SEEK_SET:
		newOffset = offset
	case os.SEEK_END:
		newOffset = hf.size + offset
	case os.SEEK_CUR:
		newOffset = hf.offset + offset
	default:
		return hf.offset, fmt.Errorf("invalid whence value %d", whence)
	}

	if newOffset < 0 {
		newOffset = 0
	}

	if newOffset > hf.size {
		newOffset = hf.size
	}

	hf.offset = newOffset
	return hf.offset, nil
}

func (hf *HTTPFile) Read(data []byte) (int, error) {
	hf.log("Read(%d)", len(data))
	bytesRead, err := hf.readAt(data, hf.offset)
	hf.offset += int64(bytesRead)
	return bytesRead, err
}

func (hf *HTTPFile) ReadAt(data []byte, offset int64) (int, error) {
	hf.log("ReadAt(%d, %d)", len(data), offset)
	return hf.readAt(data, offset)
}

func (hf *HTTPFile) readAt(data []byte, offset int64) (int, error) {
	reader, err := hf.borrowReader(offset)
	if err != nil {
		return 0, err
	}

	defer hf.returnReader(reader)

	totalBytesRead := 0
	bytesToRead := len(data)

	for totalBytesRead < bytesToRead {
		bytesRead, err := reader.Read(data[totalBytesRead:])
		hf.offset += int64(bytesRead)
		totalBytesRead += bytesRead

		if err != nil {
			if shouldRetry(err) {
				hf.log("Got %s, retrying", err.Error())
				err = reader.Connect()
				if err != nil {
					return totalBytesRead, err
				}
			} else {
				return totalBytesRead, err
			}
		}
	}

	return totalBytesRead, nil
}

func shouldRetry(err error) bool {
	if errors.Is(err, io.ErrUnexpectedEOF) {
		return true
	} else if opError, ok := err.(*net.OpError); ok {
		if opError.Timeout() || opError.Temporary() {
			return true
		} else {
			return false
		}
	} else {
		return false
	}
}

func (hf *HTTPFile) closeAllReaders() error {
	hf.readersMutex.Lock()
	defer hf.readersMutex.Unlock()

	for id, reader := range hf.readers {
		err := reader.Close()
		if err != nil {
			return err
		}

		delete(hf.readers, id)
	}

	return nil
}

func (hf *HTTPFile) Close() error {
	if hf.closed {
		return nil
	}

	err := hf.closeAllReaders()
	if err != nil {
		return err
	}

	hf.closed = true

	return nil
}

func (hf *HTTPFile) log(format string, args ...interface{}) {
	if hf.Log == nil {
		return
	}

	hf.Log(fmt.Sprintf(format, args...))
}
<commit_msg>:bug: double offset<commit_after>package httpfile

import (
	"bufio"
	"fmt"
	"io"
	"io/ioutil"
	"math"
	"net"
	"net/http"
	"net/url"
	"os"
	"sync"
	"time"

	"github.com/go-errors/errors"
	"github.com/itchio/httpkit/retrycontext"
	uuid "github.com/satori/go.uuid"
)

// A GetURLFunc returns a URL we can download the resource from.
// It's handy to have this as a function rather than a constant for signed expiring URLs
type GetURLFunc func() (urlString string, err error)

// A NeedsRenewalFunc analyzes an HTTP response and returns true if it needs to be renewed
type NeedsRenewalFunc func(res *http.Response, body []byte) bool

// A LogFunc prints debug message
type LogFunc func(msg string)

// amount we're willing to download and throw away
const maxDiscard int64 = 1 * 1024 * 1024 // 1MB

var ErrNotFound = errors.New("HTTP file not found on server")

type HTTPFile struct {
	getURL        GetURLFunc
	needsRenewal  NeedsRenewalFunc
	client        *http.Client
	retrySettings *retrycontext.Settings

	Log LogFunc

	name   string
	size   int64
	offset int64 // for io.ReadSeeker

	ReaderStaleThreshold time.Duration

	closed bool

	readers      map[string]*httpReader
	readersMutex sync.Mutex

	currentURL string
	urlMutex   sync.Mutex
}

type httpReader struct {
	file      *HTTPFile
	id        string
	touchedAt time.Time
	offset    int64
	body      io.ReadCloser
	reader    *bufio.Reader
}

const DefaultReaderStaleThreshold = time.Second * time.Duration(10)

func (hr *httpReader) Stale() bool {
	return time.Since(hr.touchedAt) > hr.file.ReaderStaleThreshold
}

func (hr *httpReader) Read(data []byte) (int, error) {
	hr.touchedAt = time.Now()
	readBytes, err := hr.reader.Read(data)
	hr.offset += int64(readBytes)

	if err != nil {
		return readBytes, err
	}
	return readBytes, nil
}

func (hr *httpReader) Discard(n int) (int, error) {
	hr.touchedAt = time.Now()
	discarded, err := hr.reader.Discard(n)
	hr.offset += int64(discarded)

	if err != nil {
		return discarded, err
	}
	return discarded, nil
}

func (hr *httpReader) Connect() error {
	if hr.body != nil {
		err := hr.body.Close()
		if err != nil {
			return err
		}

		hr.body = nil
		hr.reader = nil
	}

	tryUrl := func(urlStr string) (bool, error) {
		req, err := http.NewRequest("GET", urlStr, nil)
		if err != nil {
			return false, err
		}

		byteRange := fmt.Sprintf("bytes=%d-", hr.offset)
		req.Header.Set("Range", byteRange)

		res, err := hr.file.client.Do(req)
		if err != nil {
			return false, err
		}
		hr.file.log("did request, status %d", res.StatusCode)

		if res.StatusCode == 200 && hr.offset > 0 {
			defer res.Body.Close()

			err = fmt.Errorf("HTTP Range header not supported by %s, bailing out", req.Host)
			return false, err
		}

		if res.StatusCode/100 != 2 {
			defer res.Body.Close()

			body, err := ioutil.ReadAll(res.Body)
			if err != nil {
				body = []byte("could not read error body")
				err = nil
			}

			if hr.file.needsRenewal(res, body) {
				return true, nil
			}

			err = fmt.Errorf("HTTP %d returned by %s (%s), bailing out", res.StatusCode, req.Host, string(body))
			return false, err
		}

		hr.reader = bufio.NewReaderSize(res.Body, int(maxDiscard))
		hr.body = res.Body
		return false, nil
	}

	urlStr := hr.file.getCurrentURL()
	shouldRenew, err := tryUrl(urlStr)
	if err != nil {
		return err
	}

	if shouldRenew {
		urlStr, err = hr.file.renewURL()
		if err != nil {
			return err
		}

		shouldRenew, err = tryUrl(urlStr)
		if err != nil {
			return err
		}

		if shouldRenew {
			return fmt.Errorf("getting expired URLs from URL source (timezone issue?)")
		}
	}

	return nil
}

func (hr *httpReader) Close() error {
	err := hr.body.Close()

	if err != nil {
		return err
	}
	return nil
}

var _ io.Seeker = (*HTTPFile)(nil)
var _ io.Reader = (*HTTPFile)(nil)
var _ io.ReaderAt = (*HTTPFile)(nil)
var _ io.Closer = (*HTTPFile)(nil)

type Settings struct {
	Client        *http.Client
	RetrySettings *retrycontext.Settings
}

func New(getURL GetURLFunc, needsRenewal NeedsRenewalFunc, settings *Settings) (*HTTPFile, error) {
	client := settings.Client
	if client == nil {
		client = http.DefaultClient
	}

	retryCtx := retrycontext.NewDefault()
	if settings.RetrySettings != nil {
		retryCtx.Settings = *settings.RetrySettings
	}

	for retryCtx.ShouldTry() {
		urlStr, err := getURL()
		if err != nil {
			// this assumes getURL does its own retrying
			return nil, err
		}

		parsedUrl, err := url.Parse(urlStr)
		if err != nil {
			// can't recover from a bad url
			return nil, err
		}

		req, err := http.NewRequest("HEAD", urlStr, nil)
		if err != nil {
			// internal error
			return nil, err
		}

		res, err := client.Do(req)
		if err != nil {
			// we can recover from some client errors
			// (example: temporarily offline, DNS failure, etc.)
			retryCtx.Retry(err.Error())
			continue
		}

		if res.StatusCode != 200 {
			if res.StatusCode == 404 {
				// no need to retry - it's not coming back
				return nil, errors.Wrap(ErrNotFound, 1)
			}

			body, _ := ioutil.ReadAll(res.Body)
			if needsRenewal(res, body) {
				retryCtx.Retry(fmt.Sprintf("HTTP %d (needs renewal)", res.StatusCode))
				continue
			}

			if res.StatusCode == 429 || res.StatusCode/100 == 5 {
				retryCtx.Retry(fmt.Sprintf("HTTP %d (retrying)", res.StatusCode))
				continue
			}

			return nil, fmt.Errorf("Expected HTTP 200, got HTTP %d, not retrying", res.StatusCode)
		}

		hf := &HTTPFile{
			currentURL:    urlStr,
			getURL:        getURL,
			retrySettings: &retryCtx.Settings,
			needsRenewal:  needsRenewal,
			client:        client,

			name:    parsedUrl.Path,
			size:    res.ContentLength,
			readers: make(map[string]*httpReader),

			ReaderStaleThreshold: DefaultReaderStaleThreshold,
		}
		return hf, nil
	}

	return nil, fmt.Errorf("Could not access remote file. Last error: %s", retryCtx.LastMessage)
}

func (hf *HTTPFile) NumReaders() int {
	return len(hf.readers)
}

func (hf *HTTPFile) borrowReader(offset int64) (*httpReader, error) {
	hf.readersMutex.Lock()
	defer hf.readersMutex.Unlock()

	var bestReader string
	var bestDiff int64 = math.MaxInt64

	for _, reader := range hf.readers {
		if reader.Stale() {
			delete(hf.readers, reader.id)

			err := reader.Close()
			if err != nil {
				return nil, err
			}
			continue
		}

		diff := offset - reader.offset
		if diff >= 0 && diff < maxDiscard {
			if diff < bestDiff {
				bestReader = reader.id
				bestDiff = diff
			}
		}
	}

	if bestReader != "" {
		// re-use!
		reader := hf.readers[bestReader]
		delete(hf.readers, bestReader)

		// discard if needed
		if bestDiff > 0 {
			hf.log("borrow: for %d, re-using %d by discarding %d bytes", offset, reader.offset, bestDiff)

			// XXX: not int64-clean
			_, err := reader.Discard(int(bestDiff))
			if err != nil {
				if shouldRetry(err) {
					hf.log("borrow: for %d, discard failed because of retriable error, reconnecting", offset)
					reader.offset = offset
					err = reader.Connect()
					if err != nil {
						return nil, err
					}
				} else {
					return nil, err
				}
			}
		}

		return reader, nil
	}

	// provision a new reader
	hf.log("borrow: making fresh for offset %d", offset)

	reader := &httpReader{
		file:      hf,
		id:        uuid.NewV4().String(),
		touchedAt: time.Now(),
		offset:    offset,
	}

	err := reader.Connect()
	if err != nil {
		return nil, err
	}

	return reader, nil
}

func (hf *HTTPFile) returnReader(reader *httpReader) {
	hf.readersMutex.Lock()
	defer hf.readersMutex.Unlock()

	// TODO: enforce max idle readers ?

	reader.touchedAt = time.Now()
	hf.readers[reader.id] = reader
}

func (hf *HTTPFile) getCurrentURL() string {
	hf.urlMutex.Lock()
	defer hf.urlMutex.Unlock()

	return hf.currentURL
}

func (hf *HTTPFile) renewURL() (string, error) {
	hf.urlMutex.Lock()
	defer hf.urlMutex.Unlock()

	urlStr, err := hf.getURL()
	if err != nil {
		return "", err
	}

	hf.currentURL = urlStr
	return hf.currentURL, nil
}

func (hf *HTTPFile) Stat() (os.FileInfo, error) {
	return &httpFileInfo{hf}, nil
}

func (hf *HTTPFile) Seek(offset int64, whence int) (int64, error) {
	var newOffset int64

	switch whence {
	case os.SEEK_SET:
		newOffset = offset
	case os.SEEK_END:
		newOffset = hf.size + offset
	case os.SEEK_CUR:
		newOffset = hf.offset + offset
	default:
		return hf.offset, fmt.Errorf("invalid whence value %d", whence)
	}

	if newOffset < 0 {
		newOffset = 0
	}

	if newOffset > hf.size {
		newOffset = hf.size
	}

	hf.offset = newOffset
	return hf.offset, nil
}

func (hf *HTTPFile) Read(data []byte) (int, error) {
	hf.log("Read(%d)", len(data))
	bytesRead, err := hf.readAt(data, hf.offset)
	hf.offset += int64(bytesRead)
	return bytesRead, err
}

func (hf *HTTPFile) ReadAt(data []byte, offset int64) (int, error) {
	hf.log("ReadAt(%d, %d)", len(data), offset)
	return hf.readAt(data, offset)
}

func (hf *HTTPFile) readAt(data []byte, offset int64) (int, error) {
	reader, err := hf.borrowReader(offset)
	if err != nil {
		return 0, err
	}

	defer hf.returnReader(reader)

	totalBytesRead := 0
	bytesToRead := len(data)

	for totalBytesRead < bytesToRead {
		bytesRead, err := reader.Read(data[totalBytesRead:])
		totalBytesRead += bytesRead

		if err != nil {
			if shouldRetry(err) {
				hf.log("Got %s, retrying", err.Error())
				err = reader.Connect()
				if err != nil {
					return totalBytesRead, err
				}
			} else {
				return totalBytesRead, err
			}
		}
	}

	return totalBytesRead, nil
}

func shouldRetry(err error) bool {
	if errors.Is(err, io.ErrUnexpectedEOF) {
		return true
	} else if opError, ok := err.(*net.OpError); ok {
		if opError.Timeout() || opError.Temporary() {
			return true
		} else {
			return false
		}
	} else {
		return false
	}
}

func (hf *HTTPFile) closeAllReaders() error {
	hf.readersMutex.Lock()
	defer hf.readersMutex.Unlock()

	for id, reader := range hf.readers {
		err := reader.Close()
		if err != nil {
			return err
		}

		delete(hf.readers, id)
	}

	return nil
}

func (hf *HTTPFile) Close() error {
	if hf.closed {
		return nil
	}

	err := hf.closeAllReaders()
	if err != nil {
		return err
	}

	hf.closed = true

	return nil
}

func (hf *HTTPFile) log(format string, args ...interface{}) {
	if hf.Log == nil {
		return
	}

	hf.Log(fmt.Sprintf(format, args...))
}
<|endoftext|>


<commit_before>package gock

// Version defines the current package semantic version.
const Version = "1.1.0"
<commit_msg>feat: bump version<commit_after>package gock

// Version defines the current package semantic version.
const Version = "1.1.1"
<|endoftext|>


<commit_before>// Copyright 2018 The Moov Authors
// Use of this source code is governed by an Apache License
// license that can be found in the LICENSE file.

package ach

// Version Number
const Version = "v0.5.1-dev"
<commit_msg>release v0.6.0-rc1<commit_after>// Copyright 2018 The Moov Authors
// Use of this source code is governed by an Apache License
// license that can be found in the LICENSE file.

package ach

// Version Number
const Version = "v0.6.0-rc1"
<|endoftext|>


<commit_before>package main

const Name string = "spl"
const Version string = "0.1.0"
<commit_msg>main: add comments in version.go<commit_after>package main

// Name is an app name.
const Name string = "spl"

// Version is an app version.
const Version string = "0.1.0"
<|endoftext|>


<commit_before>package main
const (
    appVersion=1
)<commit_msg>upped version<commit_after>package main

const (
	appVersion = 2
)
<|endoftext|>


<commit_before>package main

const Version = "v1.4.6"
<commit_msg>version bump: v1.4.7<commit_after>package main

const Version = "v1.4.7"
<|endoftext|>


<commit_before>package main

const Name string = "aurl"
const Version string = "1.1-SNAPSHOT"
const Author string = "Daisuke Miyamoto <miyamoto.daisuke@classmethod.jp>"
<commit_msg>bump version<commit_after>package main

const Name string = "aurl"
const Version string = "1.0.1"
const Author string = "Daisuke Miyamoto <miyamoto.daisuke@classmethod.jp>"
<|endoftext|>


<commit_before>package atlas

const ourVersion = "0.3"
<commit_msg>Fix API for creating measurements.<commit_after>package atlas

const ourVersion = "0.3.1"
<|endoftext|>


<commit_before>package swag

// Version of swag.
const Version = "v1.8.7"
<commit_msg>chore: increment version.go (#1395)<commit_after>package swag

// Version of swag.
const Version = "v1.8.8"
<|endoftext|>


<commit_before>package util

import (
	"fmt"
	"runtime"
)

// VersionString returns a version string that should be printed with the -v
// or the --version flag. It gets the components from the following keys from
// the options:
// program-name
// program-version
// program-timestamp
func VersionString(opts Options) string {
	progName := opts.Get("program-name", "undefined")
	progVersion := opts.Get("program-version", "undefined")
	progTimestamp := opts.Get("program-timestamp", "undefined")

	return fmt.Sprintf("%s: %s\nBuilt %v with: %s/%s for %s/%s",
		progName, progVersion, progTimestamp, runtime.Compiler,
		runtime.Version(), runtime.GOOS, runtime.GOARCH)
}
<commit_msg>version: Add displaying OS and ARCH the binary was built on<commit_after>package util

import (
	"fmt"
	"runtime"
)

// VersionString returns a version string that should be printed with the -v
// or the --version flag. It gets the components from the following keys from
// the options:
// program-name
// program-version
// program-timestamp
func VersionString(opts Options) string {
	progName := opts.Get("program-name", "undefined")
	progVersion := opts.Get("program-version", "undefined")
	progTimestamp := opts.Get("program-timestamp", "undefined")

	rest := ""
	if opts.IsSet("program-buildgoos") {
		rest = fmt.Sprintf("\nBuilt on %s/%s",
			opts.Get("program-buildgoos", ""),
			opts.Get("program-buildgoarch", ""))
	}

	return fmt.Sprintf("%s: %s\nBuilt %v with: %s/%s for %s/%s%s",
		progName, progVersion, progTimestamp, runtime.Compiler,
		runtime.Version(), runtime.GOOS, runtime.GOARCH, rest)
}
<|endoftext|>


<commit_before>// Copyright (c) 2021 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package tally

// Version is the current version of the library.
const Version = "3.4.0"
<commit_msg>Prepare v3.4.1<commit_after>// Copyright (c) 2021 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package tally

// Version is the current version of the library.
const Version = "3.4.1"
<|endoftext|>


<commit_before>// nsq is the official Go package for https://github.com/bitly/nsq
//
// It provides high-level Reader and Writer types to implement consumers and
// producers as well as low-level functions to communicate over the NSQ protocol.
package nsq

const VERSION = "0.3.2"
<commit_msg>bump to 0.3.3-alpha<commit_after>// nsq is the official Go package for https://github.com/bitly/nsq
//
// It provides high-level Reader and Writer types to implement consumers and
// producers as well as low-level functions to communicate over the NSQ protocol.
package nsq

const VERSION = "0.3.3-alpha"
<|endoftext|>


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

package goacme

import (
	"crypto/rand"
	"crypto/rsa"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"net/http"
	"net/http/httptest"
	"reflect"
	"testing"
)

// Decodes a JWS-encoded request and unmarshals the decoded JSON into a provided
// interface.
func decodeJWSRequest(t *testing.T, v interface{}, r *http.Request) {
	// Decode request
	var req struct{ Payload string }
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		t.Fatal(err)
	}
	payload, err := base64.RawURLEncoding.DecodeString(req.Payload)
	if err != nil {
		t.Fatal(err)
	}
	err = json.Unmarshal(payload, v)
	if err != nil {
		t.Fatal(err)
	}
}

func TestDiscover(t *testing.T) {
	const (
		reg    = "https://example.com/acme/new-reg"
		authz  = "https://example.com/acme/new-authz"
		cert   = "https://example.com/acme/new-cert"
		revoke = "https://example.com/acme/revoke-cert"
	)
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("content-type", "application/json")
		fmt.Fprintf(w, `{
			"new-reg": %q,
			"new-authz": %q,
			"new-cert": %q,
			"revoke-cert": %q
		}`, reg, authz, cert, revoke)
	}))
	defer ts.Close()
	ep, err := Discover(nil, ts.URL)
	if err != nil {
		t.Fatal(err)
	}
	if ep.RegURL != reg {
		t.Errorf("RegURL = %q; want %q", ep.RegURL, reg)
	}
	if ep.AuthzURL != authz {
		t.Errorf("authzURL = %q; want %q", ep.AuthzURL, authz)
	}
	if ep.CertURL != cert {
		t.Errorf("certURL = %q; want %q", ep.CertURL, cert)
	}
	if ep.RevokeURL != revoke {
		t.Errorf("revokeURL = %q; want %q", ep.RevokeURL, revoke)
	}
}

func TestRegister(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.Method == "HEAD" {
			w.Header().Set("replay-nonce", "test-nonce")
			return
		}
		if r.Method != "POST" {
			t.Errorf("r.Method = %q; want POST", r.Method)
		}
		w.WriteHeader(http.StatusCreated)
	}))
	defer ts.Close()
	key, err := rsa.GenerateKey(rand.Reader, 2048)
	if err != nil {
		t.Fatal(err)
	}
	cfg := &Config{
		Key:      key,
		Endpoint: Endpoint{RegURL: ts.URL},
	}
	if err := Register(nil, cfg); err != nil {
		t.Fatal(err)
	}
}

func TestAuthorize(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.Method == "HEAD" {
			w.Header().Set("replay-nonce", "test-nonce")
			return
		}
		if r.Method != "POST" {
			t.Errorf("r.Method = %q; want POST", r.Method)
		}
		w.WriteHeader(http.StatusCreated)
		fmt.Fprintf(w, `{
			"identifier": {"type":"dns","value":"example.com"},
			"status":"pending",
			"challenges":[
				{
					"type":"http-01",
					"status":"pending",
					"uri":"https://ca.tld/acme/challenge/publickey/id1",
					"token":"token1"
				},
				{
					"type":"tls-sni-01",
					"status":"pending",
					"uri":"https://ca.tld/acme/challenge/publickey/id2",
					"token":"token2"
				}
			],
			"combinations":[[0],[1]]}`)
	}))
	defer ts.Close()
	key, err := rsa.GenerateKey(rand.Reader, 2048)
	if err != nil {
		t.Fatal(err)
	}
	cfg := &Config{
		Key:      key,
		Endpoint: Endpoint{AuthzURL: ts.URL},
	}
	set, err := authorize(nil, cfg, "example.com")
	if err != nil {
		t.Fatal(err)
	}
	if n := len(set.Challenges); n != 2 {
		t.Fatalf("len(set.Challenges) = %d; want 2", n)
	}

	c := set.Challenges[0]
	if c.Type != "http-01" {
		t.Errorf("c.Type = %q; want http-01", c.Type)
	}
	if c.URI != "https://ca.tld/acme/challenge/publickey/id1" {
		t.Errorf("c.URI = %q; want https://ca.tld/acme/challenge/publickey/id1", c.URI)
	}
	if c.Token != "token1" {
		t.Errorf("c.Token = %q; want token1", c.Type)
	}

	c = set.Challenges[1]
	if c.Type != "tls-sni-01" {
		t.Errorf("c.Type = %q; want tls-sni-01", c.Type)
	}
	if c.URI != "https://ca.tld/acme/challenge/publickey/id2" {
		t.Errorf("c.URI = %q; want https://ca.tld/acme/challenge/publickey/id2", c.URI)
	}
	if c.Token != "token2" {
		t.Errorf("c.Token = %q; want token2", c.Type)
	}

	combs := [][]int{[]int{0}, []int{1}}
	if !reflect.DeepEqual(set.Combinations, combs) {
		t.Errorf("set.Combinations: %+v\nwant: %+v\n", set.Combinations, combs)
	}
}

func TestAcceptChallenge(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.Method == "HEAD" {
			w.Header().Set("replay-nonce", "test-nonce")
			return
		}
		if r.Method != "POST" {
			t.Errorf("r.Method = %q; want POST", r.Method)
		}

		var j struct {
			Resource string
			Type     string
			Auth     string `json:"keyAuthorization"`
		}
		decodeJWSRequest(t, &j, r)

		// Test request
		if j.Resource != "challenge" {
			t.Errorf(`resource = %q; want "challenge"`, j.Resource)
		}
		if j.Type != "http-01" {
			t.Errorf(`type = %q; want "http-01"`, j.Type)
		}
		keyAuth := "token1." + testKeyThumbprint
		if j.Auth != keyAuth {
			t.Errorf(`keyAuthorization = %q; want %q`, j.Auth, keyAuth)
		}

		// Respond to request
		w.WriteHeader(http.StatusAccepted)
		fmt.Fprintf(w, `{
			"type":"http-01",
			"status":"pending",
			"uri":"https://ca.tld/acme/challenge/publickey/id1",
			"token":"token1",
			"keyAuthorization":%q
		}`, keyAuth)
	}))
	defer ts.Close()
	c, err := acceptChallenge(nil, &Config{Key: testKey}, Challenge{
		URI:   ts.URL,
		Token: "token1",
		Type:  "http-01",
	})
	if err != nil {
		t.Fatal(err)
	}

	if c.Type != "http-01" {
		t.Errorf("c.Type = %q; want http-01", c.Type)
	}
	if c.URI != "https://ca.tld/acme/challenge/publickey/id1" {
		t.Errorf("c.URI = %q; want https://ca.tld/acme/challenge/publickey/id1", c.URI)
	}
	if c.Token != "token1" {
		t.Errorf("c.Token = %q; want token1", c.Type)
	}
}

func TestFetchNonce(t *testing.T) {
	tests := []struct {
		code  int
		nonce string
	}{
		{http.StatusOK, "nonce1"},
		{http.StatusBadRequest, "nonce2"},
		{http.StatusOK, ""},
	}
	var i int
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.Method != "HEAD" {
			t.Errorf("%d: r.Method = %q; want HEAD", i, r.Method)
		}
		w.Header().Set("replay-nonce", tests[i].nonce)
		w.WriteHeader(tests[i].code)
	}))
	defer ts.Close()
	for ; i < len(tests); i++ {
		test := tests[i]
		n, err := fetchNonce(http.DefaultClient, ts.URL)
		if n != test.nonce {
			t.Errorf("%d: n=%q; want %q", i, n, test.nonce)
		}
		switch {
		case err == nil && test.nonce == "":
			t.Errorf("%d: n=%q, err=%v; want non-nil error", i, n, err)
		case err != nil && test.nonce != "":
			t.Errorf("%d: n=%q, err=%v; want %q", i, n, err, test.nonce)
		}
	}
}

func TestParseLinkHeader(t *testing.T) {
	h := http.Header{"Link": {
		`<https://example.com/acme/new-authz>;rel="next"`,
		`<https://example.com/acme/recover-reg>; rel=recover`,
		`<https://example.com/acme/terms>; foo=bar; rel="terms-of-service"`,
	}}
	tests := []struct{ in, out string }{
		{"next", "https://example.com/acme/new-authz"},
		{"recover", "https://example.com/acme/recover-reg"},
		{"terms-of-service", "https://example.com/acme/terms"},
		{"empty", ""},
	}
	for i, test := range tests {
		if v := parseLinkHeader(h, test.in); v != test.out {
			t.Errorf("%d: parseLinkHeader(%q): %q; want %q", i, test.in, v, test.out)
		}
	}
}
<commit_msg>Adding some more tests for existing methods<commit_after>// Copyright 2015 Google Inc. All Rights Reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//     http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package goacme

import (
	"crypto/rand"
	"crypto/rsa"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"net/http"
	"net/http/httptest"
	"reflect"
	"testing"
)

// Decodes a JWS-encoded request and unmarshals the decoded JSON into a provided
// interface.
func decodeJWSRequest(t *testing.T, v interface{}, r *http.Request) {
	// Decode request
	var req struct{ Payload string }
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		t.Fatal(err)
	}
	payload, err := base64.RawURLEncoding.DecodeString(req.Payload)
	if err != nil {
		t.Fatal(err)
	}
	err = json.Unmarshal(payload, v)
	if err != nil {
		t.Fatal(err)
	}
}

func TestDiscover(t *testing.T) {
	const (
		reg    = "https://example.com/acme/new-reg"
		authz  = "https://example.com/acme/new-authz"
		cert   = "https://example.com/acme/new-cert"
		revoke = "https://example.com/acme/revoke-cert"
	)
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("content-type", "application/json")
		fmt.Fprintf(w, `{
			"new-reg": %q,
			"new-authz": %q,
			"new-cert": %q,
			"revoke-cert": %q
		}`, reg, authz, cert, revoke)
	}))
	defer ts.Close()
	ep, err := Discover(nil, ts.URL)
	if err != nil {
		t.Fatal(err)
	}
	if ep.RegURL != reg {
		t.Errorf("RegURL = %q; want %q", ep.RegURL, reg)
	}
	if ep.AuthzURL != authz {
		t.Errorf("authzURL = %q; want %q", ep.AuthzURL, authz)
	}
	if ep.CertURL != cert {
		t.Errorf("certURL = %q; want %q", ep.CertURL, cert)
	}
	if ep.RevokeURL != revoke {
		t.Errorf("revokeURL = %q; want %q", ep.RevokeURL, revoke)
	}
}

func TestRegister(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.Method == "HEAD" {
			w.Header().Set("replay-nonce", "test-nonce")
			return
		}
		if r.Method != "POST" {
			t.Errorf("r.Method = %q; want POST", r.Method)
		}

		var j struct {
			Resource  string
			Contact   []string
			Agreement string
		}
		decodeJWSRequest(t, &j, r)

		// Test request
		if j.Resource != "new-reg" {
			t.Errorf(`resource = %q; want "new-reg"`, j.Resource)
		}
		if len(j.Contact) != 1 || j.Contact[0] != "mailto:admin@example.com" {
			t.Errorf(`contact = %v; want [mailto:admin@example.com]`, j.Contact)
		}
		if j.Agreement != "http://www.example.com" {
			t.Errorf(`agreement = %q; want "http://www.example.com"`, j.Agreement)
		}

		w.WriteHeader(http.StatusCreated)
	}))
	defer ts.Close()
	key, err := rsa.GenerateKey(rand.Reader, 2048)
	if err != nil {
		t.Fatal(err)
	}
	cfg := &Config{
		Key:      key,
		Contact:  []string{"mailto:admin@example.com"},
		Endpoint: Endpoint{RegURL: ts.URL},
		TermsURI: "http://www.example.com",
	}
	// Test response handling
	if err := Register(nil, cfg); err != nil {
		t.Fatal(err)
	}
}

func TestAuthorize(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.Method == "HEAD" {
			w.Header().Set("replay-nonce", "test-nonce")
			return
		}
		if r.Method != "POST" {
			t.Errorf("r.Method = %q; want POST", r.Method)
		}

		var j struct {
			Resource   string
			Identifier AuthzIdentifier
		}
		decodeJWSRequest(t, &j, r)

		// Test request
		if j.Resource != "new-authz" {
			t.Errorf(`resource = %q; want "new-authz"`, j.Resource)
		}
		if j.Identifier.Type != "dns" {
			t.Errorf(`identifier.type = %q; want "dns"`, j.Identifier.Type)
		}
		if j.Identifier.Value != "example.com" {
			t.Errorf(`identifier.value = %q; want "example.com"`, j.Identifier.Value)
		}

		w.WriteHeader(http.StatusCreated)
		fmt.Fprintf(w, `{
			"identifier": {"type":"dns","value":"example.com"},
			"status":"pending",
			"challenges":[
				{
					"type":"http-01",
					"status":"pending",
					"uri":"https://ca.tld/acme/challenge/publickey/id1",
					"token":"token1"
				},
				{
					"type":"tls-sni-01",
					"status":"pending",
					"uri":"https://ca.tld/acme/challenge/publickey/id2",
					"token":"token2"
				}
			],
			"combinations":[[0],[1]]}`)
	}))
	defer ts.Close()
	cfg := &Config{
		Key:      testKey,
		Endpoint: Endpoint{AuthzURL: ts.URL},
	}

	// Test response handling
	set, err := authorize(nil, cfg, "example.com")
	if err != nil {
		t.Fatal(err)
	}
	if n := len(set.Challenges); n != 2 {
		t.Fatalf("len(set.Challenges) = %d; want 2", n)
	}

	c := set.Challenges[0]
	if c.Type != "http-01" {
		t.Errorf("c.Type = %q; want http-01", c.Type)
	}
	if c.URI != "https://ca.tld/acme/challenge/publickey/id1" {
		t.Errorf("c.URI = %q; want https://ca.tld/acme/challenge/publickey/id1", c.URI)
	}
	if c.Token != "token1" {
		t.Errorf("c.Token = %q; want token1", c.Type)
	}

	c = set.Challenges[1]
	if c.Type != "tls-sni-01" {
		t.Errorf("c.Type = %q; want tls-sni-01", c.Type)
	}
	if c.URI != "https://ca.tld/acme/challenge/publickey/id2" {
		t.Errorf("c.URI = %q; want https://ca.tld/acme/challenge/publickey/id2", c.URI)
	}
	if c.Token != "token2" {
		t.Errorf("c.Token = %q; want token2", c.Type)
	}

	combs := [][]int{[]int{0}, []int{1}}
	if !reflect.DeepEqual(set.Combinations, combs) {
		t.Errorf("set.Combinations: %+v\nwant: %+v\n", set.Combinations, combs)
	}
}

func TestAcceptChallenge(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.Method == "HEAD" {
			w.Header().Set("replay-nonce", "test-nonce")
			return
		}
		if r.Method != "POST" {
			t.Errorf("r.Method = %q; want POST", r.Method)
		}

		var j struct {
			Resource string
			Type     string
			Auth     string `json:"keyAuthorization"`
		}
		decodeJWSRequest(t, &j, r)

		// Test request
		if j.Resource != "challenge" {
			t.Errorf(`resource = %q; want "challenge"`, j.Resource)
		}
		if j.Type != "http-01" {
			t.Errorf(`type = %q; want "http-01"`, j.Type)
		}
		keyAuth := "token1." + testKeyThumbprint
		if j.Auth != keyAuth {
			t.Errorf(`keyAuthorization = %q; want %q`, j.Auth, keyAuth)
		}

		// Respond to request
		w.WriteHeader(http.StatusAccepted)
		fmt.Fprintf(w, `{
			"type":"http-01",
			"status":"pending",
			"uri":"https://ca.tld/acme/challenge/publickey/id1",
			"token":"token1",
			"keyAuthorization":%q
		}`, keyAuth)
	}))
	defer ts.Close()

	// Test response handling
	c, err := acceptChallenge(nil, &Config{Key: testKey}, Challenge{
		URI:   ts.URL,
		Token: "token1",
		Type:  "http-01",
	})
	if err != nil {
		t.Fatal(err)
	}

	if c.Type != "http-01" {
		t.Errorf("c.Type = %q; want http-01", c.Type)
	}
	if c.URI != "https://ca.tld/acme/challenge/publickey/id1" {
		t.Errorf("c.URI = %q; want https://ca.tld/acme/challenge/publickey/id1", c.URI)
	}
	if c.Token != "token1" {
		t.Errorf("c.Token = %q; want token1", c.Type)
	}
}

func TestFetchNonce(t *testing.T) {
	tests := []struct {
		code  int
		nonce string
	}{
		{http.StatusOK, "nonce1"},
		{http.StatusBadRequest, "nonce2"},
		{http.StatusOK, ""},
	}
	var i int
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.Method != "HEAD" {
			t.Errorf("%d: r.Method = %q; want HEAD", i, r.Method)
		}
		w.Header().Set("replay-nonce", tests[i].nonce)
		w.WriteHeader(tests[i].code)
	}))
	defer ts.Close()
	for ; i < len(tests); i++ {
		test := tests[i]
		n, err := fetchNonce(http.DefaultClient, ts.URL)
		if n != test.nonce {
			t.Errorf("%d: n=%q; want %q", i, n, test.nonce)
		}
		switch {
		case err == nil && test.nonce == "":
			t.Errorf("%d: n=%q, err=%v; want non-nil error", i, n, err)
		case err != nil && test.nonce != "":
			t.Errorf("%d: n=%q, err=%v; want %q", i, n, err, test.nonce)
		}
	}
}

func TestParseLinkHeader(t *testing.T) {
	h := http.Header{"Link": {
		`<https://example.com/acme/new-authz>;rel="next"`,
		`<https://example.com/acme/recover-reg>; rel=recover`,
		`<https://example.com/acme/terms>; foo=bar; rel="terms-of-service"`,
	}}
	tests := []struct{ in, out string }{
		{"next", "https://example.com/acme/new-authz"},
		{"recover", "https://example.com/acme/recover-reg"},
		{"terms-of-service", "https://example.com/acme/terms"},
		{"empty", ""},
	}
	for i, test := range tests {
		if v := parseLinkHeader(h, test.in); v != test.out {
			t.Errorf("%d: parseLinkHeader(%q): %q; want %q", i, test.in, v, test.out)
		}
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2017 Intel Corporation
//
// 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.

// This is a "Multi-plugin".The delegate concept refered from CNI project
// It reads other plugin netconf, and then invoke them, e.g.
// flannel or sriov plugin.

package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"

	"github.com/containernetworking/cni/pkg/invoke"
	"github.com/containernetworking/cni/pkg/skel"
	cnitypes "github.com/containernetworking/cni/pkg/types"
	"github.com/containernetworking/cni/pkg/version"
	"github.com/containernetworking/plugins/pkg/ns"
	k8s "github.com/intel/multus-cni/k8sclient"
	"github.com/intel/multus-cni/types"
	"github.com/vishvananda/netlink"
)

func saveScratchNetConf(containerID, dataDir string, netconf []byte) error {
	if err := os.MkdirAll(dataDir, 0700); err != nil {
		return fmt.Errorf("failed to create the multus data directory(%q): %v", dataDir, err)
	}

	path := filepath.Join(dataDir, containerID)

	err := ioutil.WriteFile(path, netconf, 0600)
	if err != nil {
		return fmt.Errorf("failed to write container data in the path(%q): %v", path, err)
	}

	return err
}

func consumeScratchNetConf(containerID, dataDir string) ([]byte, error) {
	path := filepath.Join(dataDir, containerID)
	defer os.Remove(path)

	return ioutil.ReadFile(path)
}

func getIfname(delegate *types.DelegateNetConf, argif string, idx int) string {
	if delegate.IfnameRequest != "" {
		return delegate.IfnameRequest
	}
	if delegate.MasterPlugin {
		// master plugin always uses the CNI-provided interface name
		return argif
	}

	// Otherwise construct a unique interface name from the delegate's
	// position in the delegate list
	return fmt.Sprintf("net%d", idx)
}

func saveDelegates(containerID, dataDir string, delegates []*types.DelegateNetConf) error {
	delegatesBytes, err := json.Marshal(delegates)
	if err != nil {
		return fmt.Errorf("error serializing delegate netconf: %v", err)
	}

	if err = saveScratchNetConf(containerID, dataDir, delegatesBytes); err != nil {
		return fmt.Errorf("error in saving the  delegates : %v", err)
	}

	return err
}

func validateIfName(nsname string, ifname string) error {
	podNs, err := ns.GetNS(nsname)
	if err != nil {
		return fmt.Errorf("no netns: %v", err)
	}

	err = podNs.Do(func(_ ns.NetNS) error {
		_, err := netlink.LinkByName(ifname)
		if err != nil {
			if err.Error() == "Link not found" {
				return nil
			}
			return err
		}
		return fmt.Errorf("ifname %s is already exist", ifname)
	})

	return err
}

func delegateAdd(exec invoke.Exec, ifName string, delegate *types.DelegateNetConf) (cnitypes.Result, error) {
	if os.Setenv("CNI_IFNAME", ifName) != nil {
		return nil, fmt.Errorf("Multus: error in setting CNI_IFNAME")
	}

	if err := validateIfName(os.Getenv("CNI_NETNS"), ifName); err != nil {
		return nil, fmt.Errorf("cannot set %q ifname to %q: %v", delegate.Type, ifName, err)
	}

	result, err := invoke.DelegateAdd(delegate.Type, delegate.Bytes, exec)
	if err != nil {
		return nil, fmt.Errorf("Multus: error in invoke Delegate add - %q: %v", delegate.Type, err)
	}

	return result, nil
}

func delegateDel(exec invoke.Exec, ifName string, delegateConf *types.DelegateNetConf) error {
	if os.Setenv("CNI_IFNAME", ifName) != nil {
		return fmt.Errorf("Multus: error in setting CNI_IFNAME")
	}

	if err := invoke.DelegateDel(delegateConf.Type, delegateConf.Bytes, exec); err != nil {
		return fmt.Errorf("Multus: error in invoke Delegate del - %q: %v", delegateConf.Type, err)
	}

	return nil
}

func delPlugins(exec invoke.Exec, argIfname string, delegates []*types.DelegateNetConf, lastIdx int) error {
	if os.Setenv("CNI_COMMAND", "DEL") != nil {
		return fmt.Errorf("Multus: error in setting CNI_COMMAND to DEL")
	}

	for idx := lastIdx; idx >= 0; idx-- {
		ifName := getIfname(delegates[idx], argIfname, idx)
		if err := delegateDel(exec, ifName, delegates[idx]); err != nil {
			return err
		}
	}

	return nil
}

func cmdAdd(args *skel.CmdArgs, exec invoke.Exec) error {
	var nopodnet bool
	n, err := types.LoadNetConf(args.StdinData)
	if err != nil {
		return fmt.Errorf("err in loading netconf: %v", err)
	}

	if n.Kubeconfig != "" {
		delegates, err := k8s.GetK8sNetwork(args, n.Kubeconfig, n.ConfDir)
		if err != nil {
			if _, ok := err.(*k8s.NoK8sNetworkError); ok {
				nopodnet = true
			} else {
				return fmt.Errorf("Multus: Err in getting k8s network from pod: %v", err)
			}
		}

		if err = n.AddDelegates(delegates); err != nil {
			return err
		}
	}

	if n.Kubeconfig == "" || nopodnet {
		if err := saveDelegates(args.ContainerID, n.CNIDir, n.Delegates); err != nil {
			return fmt.Errorf("Multus: Err in saving the delegates: %v", err)
		}
	}

	var result, tmpResult cnitypes.Result
	lastIdx := 0
	for idx, delegate := range n.Delegates {
		lastIdx = idx
		ifName := getIfname(delegate, args.IfName, idx)
		tmpResult, err = delegateAdd(exec, ifName, delegate)
		if err != nil {
			break
		}

		// Master plugin result is always used if present
		if delegate.MasterPlugin || result == nil {
			result = tmpResult
		}
	}
	if err != nil {
		// Ignore errors; DEL must be idempotent anyway
		_ = delPlugins(exec, args.IfName, n.Delegates, lastIdx)
		return err
	}

	return result.Print()
}

func cmdGet(args *skel.CmdArgs, exec invoke.Exec) error {
	in, err := types.LoadNetConf(args.StdinData)
	if err != nil {
		return err
	}

	// FIXME: call all delegates

	return in.PrevResult.Print()
}

func cmdDel(args *skel.CmdArgs, exec invoke.Exec) error {
	var nopodnet bool

	in, err := types.LoadNetConf(args.StdinData)
	if err != nil {
		return err
	}

	if in.Kubeconfig != "" {
		delegates, r := k8s.GetK8sNetwork(args, in.Kubeconfig, in.ConfDir)
		if r != nil {
			if _, ok := r.(*k8s.NoK8sNetworkError); ok {
				nopodnet = true
			} else {
				return fmt.Errorf("Multus: Err in getting k8s network from pod: %v", r)
			}
		}

		if err = in.AddDelegates(delegates); err != nil {
			return err
		}
	}

	if in.Kubeconfig == "" || nopodnet {
		netconfBytes, err := consumeScratchNetConf(args.ContainerID, in.CNIDir)
		if err != nil {
			if os.IsNotExist(err) {
				// Per spec should ignore error if resources are missing / already removed
				return nil
			}
			return fmt.Errorf("Multus: Err in  reading the delegates: %v", err)
		}

		if err := json.Unmarshal(netconfBytes, &in.Delegates); err != nil {
			return fmt.Errorf("Multus: failed to load netconf: %v", err)
		}
	}

	return delPlugins(exec, args.IfName, in.Delegates, len(in.Delegates)-1)
}

func main() {
	skel.PluginMain(
		func(args *skel.CmdArgs) error { return cmdAdd(args, nil) },
		func(args *skel.CmdArgs) error { return cmdGet(args, nil) },
		func(args *skel.CmdArgs) error { return cmdDel(args, nil) },
		version.All, "meta-plugin that delegates to other CNI plugins")
}
<commit_msg>multus: rework cmdAdd/Del/Get calling to support testcases<commit_after>// Copyright (c) 2017 Intel Corporation
//
// 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.

// This is a "Multi-plugin".The delegate concept refered from CNI project
// It reads other plugin netconf, and then invoke them, e.g.
// flannel or sriov plugin.

package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"

	"github.com/containernetworking/cni/pkg/invoke"
	"github.com/containernetworking/cni/pkg/skel"
	cnitypes "github.com/containernetworking/cni/pkg/types"
	"github.com/containernetworking/cni/pkg/version"
	"github.com/containernetworking/plugins/pkg/ns"
	k8s "github.com/intel/multus-cni/k8sclient"
	"github.com/intel/multus-cni/types"
	"github.com/vishvananda/netlink"
)

func saveScratchNetConf(containerID, dataDir string, netconf []byte) error {
	if err := os.MkdirAll(dataDir, 0700); err != nil {
		return fmt.Errorf("failed to create the multus data directory(%q): %v", dataDir, err)
	}

	path := filepath.Join(dataDir, containerID)

	err := ioutil.WriteFile(path, netconf, 0600)
	if err != nil {
		return fmt.Errorf("failed to write container data in the path(%q): %v", path, err)
	}

	return err
}

func consumeScratchNetConf(containerID, dataDir string) ([]byte, error) {
	path := filepath.Join(dataDir, containerID)
	defer os.Remove(path)

	return ioutil.ReadFile(path)
}

func getIfname(delegate *types.DelegateNetConf, argif string, idx int) string {
	if delegate.IfnameRequest != "" {
		return delegate.IfnameRequest
	}
	if delegate.MasterPlugin {
		// master plugin always uses the CNI-provided interface name
		return argif
	}

	// Otherwise construct a unique interface name from the delegate's
	// position in the delegate list
	return fmt.Sprintf("net%d", idx)
}

func saveDelegates(containerID, dataDir string, delegates []*types.DelegateNetConf) error {
	delegatesBytes, err := json.Marshal(delegates)
	if err != nil {
		return fmt.Errorf("error serializing delegate netconf: %v", err)
	}

	if err = saveScratchNetConf(containerID, dataDir, delegatesBytes); err != nil {
		return fmt.Errorf("error in saving the  delegates : %v", err)
	}

	return err
}

func validateIfName(nsname string, ifname string) error {
	podNs, err := ns.GetNS(nsname)
	if err != nil {
		return fmt.Errorf("no netns: %v", err)
	}

	err = podNs.Do(func(_ ns.NetNS) error {
		_, err := netlink.LinkByName(ifname)
		if err != nil {
			if err.Error() == "Link not found" {
				return nil
			}
			return err
		}
		return fmt.Errorf("ifname %s is already exist", ifname)
	})

	return err
}

func delegateAdd(exec invoke.Exec, ifName string, delegate *types.DelegateNetConf) (cnitypes.Result, error) {
	if os.Setenv("CNI_IFNAME", ifName) != nil {
		return nil, fmt.Errorf("Multus: error in setting CNI_IFNAME")
	}

	if err := validateIfName(os.Getenv("CNI_NETNS"), ifName); err != nil {
		return nil, fmt.Errorf("cannot set %q ifname to %q: %v", delegate.Type, ifName, err)
	}

	result, err := invoke.DelegateAdd(delegate.Type, delegate.Bytes, exec)
	if err != nil {
		return nil, fmt.Errorf("Multus: error in invoke Delegate add - %q: %v", delegate.Type, err)
	}

	return result, nil
}

func delegateDel(exec invoke.Exec, ifName string, delegateConf *types.DelegateNetConf) error {
	if os.Setenv("CNI_IFNAME", ifName) != nil {
		return fmt.Errorf("Multus: error in setting CNI_IFNAME")
	}

	if err := invoke.DelegateDel(delegateConf.Type, delegateConf.Bytes, exec); err != nil {
		return fmt.Errorf("Multus: error in invoke Delegate del - %q: %v", delegateConf.Type, err)
	}

	return nil
}

func delPlugins(exec invoke.Exec, argIfname string, delegates []*types.DelegateNetConf, lastIdx int) error {
	if os.Setenv("CNI_COMMAND", "DEL") != nil {
		return fmt.Errorf("Multus: error in setting CNI_COMMAND to DEL")
	}

	for idx := lastIdx; idx >= 0; idx-- {
		ifName := getIfname(delegates[idx], argIfname, idx)
		if err := delegateDel(exec, ifName, delegates[idx]); err != nil {
			return err
		}
	}

	return nil
}

func cmdAdd(args *skel.CmdArgs, exec invoke.Exec) (cnitypes.Result, error) {
	var nopodnet bool
	n, err := types.LoadNetConf(args.StdinData)
	if err != nil {
		return nil, fmt.Errorf("err in loading netconf: %v", err)
	}

	if n.Kubeconfig != "" {
		delegates, err := k8s.GetK8sNetwork(args, n.Kubeconfig, n.ConfDir)
		if err != nil {
			if _, ok := err.(*k8s.NoK8sNetworkError); ok {
				nopodnet = true
			} else {
				return nil, fmt.Errorf("Multus: Err in getting k8s network from pod: %v", err)
			}
		}

		if err = n.AddDelegates(delegates); err != nil {
			return nil, err
		}
	}

	if n.Kubeconfig == "" || nopodnet {
		if err := saveDelegates(args.ContainerID, n.CNIDir, n.Delegates); err != nil {
			return nil, fmt.Errorf("Multus: Err in saving the delegates: %v", err)
		}
	}

	var result, tmpResult cnitypes.Result
	lastIdx := 0
	for idx, delegate := range n.Delegates {
		lastIdx = idx
		ifName := getIfname(delegate, args.IfName, idx)
		tmpResult, err = delegateAdd(exec, ifName, delegate)
		if err != nil {
			break
		}

		// Master plugin result is always used if present
		if delegate.MasterPlugin || result == nil {
			result = tmpResult
		}
	}

	if err != nil {
		// Ignore errors; DEL must be idempotent anyway
		_ = delPlugins(exec, args.IfName, n.Delegates, lastIdx)
		return nil, err
	}

	return result, nil
}

func cmdGet(args *skel.CmdArgs, exec invoke.Exec) (cnitypes.Result, error) {
	in, err := types.LoadNetConf(args.StdinData)
	if err != nil {
		return nil, err
	}

	// FIXME: call all delegates

	return in.PrevResult, nil
}

func cmdDel(args *skel.CmdArgs, exec invoke.Exec) error {
	var nopodnet bool

	in, err := types.LoadNetConf(args.StdinData)
	if err != nil {
		return err
	}

	if in.Kubeconfig != "" {
		delegates, r := k8s.GetK8sNetwork(args, in.Kubeconfig, in.ConfDir)
		if r != nil {
			if _, ok := r.(*k8s.NoK8sNetworkError); ok {
				nopodnet = true
			} else {
				return fmt.Errorf("Multus: Err in getting k8s network from pod: %v", r)
			}
		}

		if err = in.AddDelegates(delegates); err != nil {
			return err
		}
	}

	if in.Kubeconfig == "" || nopodnet {
		netconfBytes, err := consumeScratchNetConf(args.ContainerID, in.CNIDir)
		if err != nil {
			if os.IsNotExist(err) {
				// Per spec should ignore error if resources are missing / already removed
				return nil
			}
			return fmt.Errorf("Multus: Err in  reading the delegates: %v", err)
		}

		if err := json.Unmarshal(netconfBytes, &in.Delegates); err != nil {
			return fmt.Errorf("Multus: failed to load netconf: %v", err)
		}
	}

	return delPlugins(exec, args.IfName, in.Delegates, len(in.Delegates)-1)
}

func main() {
	skel.PluginMain(
		func(args *skel.CmdArgs) error {
			result, err := cmdAdd(args, nil)
			if err != nil {
				return err
			}
			return result.Print()
		},
		func(args *skel.CmdArgs) error {
			result, err := cmdGet(args, nil)
			if err != nil {
				return err
			}
			return result.Print()
		},
		func(args *skel.CmdArgs) error { return cmdDel(args, nil) },
		version.All, "meta-plugin that delegates to other CNI plugins")
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"log"
	"os"
	"testing"
)

type testParams struct {
	filename  string
	maxLength uint
}

var testcases = []struct {
	name     string
	expected string
	params   testParams
}{
	{"return in block", `testdata/ret-in-block.go:9: Dummy naked returns on 8 line function
`, testParams{
		filename:  "testdata/ret-in-block.go",
		maxLength: 0,
	}},
	{"ignore short functions", ``, testParams{
		filename:  "testdata/ret-in-block.go",
		maxLength: 10,
	}},
	{"nested function literals", `testdata/nested.go:16: Bad naked returns on 6 line function
testdata/nested.go:21: <func():20> naked returns on 2 line function
testdata/nested.go:28: <func():27> naked returns on 2 line function
testdata/nested.go:32: <func():31> naked returns on 2 line function
testdata/nested.go:36: <func():35> naked returns on 2 line function
testdata/nested.go:40: <func():39> naked returns on 2 line function
`, testParams{
		filename:  "testdata/nested.go",
		maxLength: 0,
	}},
}

func runNakedret(t *testing.T, filename string, maxLength uint, expected string) {
	t.Helper()
	defer func() {
		// Reset logging
		log.SetOutput(os.Stderr)
		log.SetFlags(log.LstdFlags)
	}()
	var logBuf bytes.Buffer
	log.SetOutput(&logBuf)
	log.SetFlags(0)

	if err := checkNakedReturns([]string{filename}, &maxLength, false); err != nil {
		t.Fatal(err)
	}
	actual := logBuf.String()
	fmt.Print(actual)
	if expected != actual {
		// t.Errorf("Unexpected output:\n-----\ngot: \n%s\nexpected: \n%v\n-----\n", actual, expected)
		t.Errorf("Unexpected output:\n-----\n%s\n-----", actual)
	}
}

func TestCheckNakedReturns(t *testing.T) {
	for _, tt := range testcases {
		t.Run(tt.name, func(t *testing.T) {
			runNakedret(t, tt.params.filename, tt.params.maxLength, tt.expected)
		})
	}
}
<commit_msg>removed trailing print statements and comments<commit_after>package main

import (
	"bytes"
	"log"
	"os"
	"testing"
)

type testParams struct {
	filename  string
	maxLength uint
}

var testcases = []struct {
	name     string
	expected string
	params   testParams
}{
	{"return in block", `testdata/ret-in-block.go:9: Dummy naked returns on 8 line function
`, testParams{
		filename:  "testdata/ret-in-block.go",
		maxLength: 0,
	}},
	{"ignore short functions", ``, testParams{
		filename:  "testdata/ret-in-block.go",
		maxLength: 10,
	}},
	{"nested function literals", `testdata/nested.go:16: Bad naked returns on 6 line function
testdata/nested.go:21: <func():20> naked returns on 2 line function
testdata/nested.go:28: <func():27> naked returns on 2 line function
testdata/nested.go:32: <func():31> naked returns on 2 line function
testdata/nested.go:36: <func():35> naked returns on 2 line function
testdata/nested.go:40: <func():39> naked returns on 2 line function
`, testParams{
		filename:  "testdata/nested.go",
		maxLength: 0,
	}},
}

func runNakedret(t *testing.T, filename string, maxLength uint, expected string) {
	t.Helper()
	defer func() {
		// Reset logging
		log.SetOutput(os.Stderr)
		log.SetFlags(log.LstdFlags)
	}()
	var logBuf bytes.Buffer
	log.SetOutput(&logBuf)
	log.SetFlags(0)

	if err := checkNakedReturns([]string{filename}, &maxLength, false); err != nil {
		t.Fatal(err)
	}
	actual := logBuf.String()
	if expected != actual {
		t.Errorf("Unexpected output:\n-----\ngot: \n%s\nexpected: \n%v\n-----\n", actual, expected)
	}
}

func TestCheckNakedReturns(t *testing.T) {
	for _, tt := range testcases {
		t.Run(tt.name, func(t *testing.T) {
			runNakedret(t, tt.params.filename, tt.params.maxLength, tt.expected)
		})
	}
}
<|endoftext|>


<commit_before><commit_msg>set block profile rate when hitting /debug/pprof/block in genapi<commit_after><|endoftext|>


<commit_before>/*
	目前使用阿里大于短信服务，本接口用于阿里大于迁移到阿里云通信后使用。
*/
package aldy

import (
	"crypto/hmac"
	"encoding/base64"

	"crypto/sha1"
	"encoding/json"

	"io/ioutil"

	"net/http"
	"net/url"
	"sort"
	"strings"
	"time"

	"github.com/satori/go.uuid"
)

// sendSmsResponse
type sendSmsResponse struct {
	Message   string
	RequestId string
	BizId     string
	Code      string
}

const (
	dyURL = "http://dysmsapi.aliyuncs.com"
)

// signHMAC 获取签名
func signHMAC(params url.Values, appSecret string) (signature string) {
	keys := []string{}
	for k := range params {
		keys = append(keys, k)
	}
	str := ""
	sort.Strings(keys)
	for _, k := range keys {
		str += "&" + url.QueryEscape(k) + "=" + url.QueryEscape(params.Get(k))
	}
	signstr := "GET&%2F&" + url.QueryEscape(str[1:])
	mac := hmac.New(sha1.New, []byte(appSecret+"&"))
	mac.Write([]byte(signstr))
	return base64.StdEncoding.EncodeToString(mac.Sum(nil))
}

// SendSMS
func SendSMS(mobileNo, signName, templateCode, paramString, appKey, appSecret string) (bool, string, error) {
	params := url.Values{}

	params.Set("Timestamp", time.Now().UTC().Format("2006-01-02T15:04:05Z"))
	params.Set("SignatureMethod", "HMAC-SHA1")
	params.Set("SignatureVersion", "1.0")
	uId := uuid.NewV4()
	params.Set("SignatureNonce", strings.ToLower(uId.String()))
	params.Set("AccessKeyId", appKey)
	params.Add("Format", "JSON")
	params.Set("RegionId", "cn-hangzhou")

	params.Set("SignName", signName)
	params.Set("TemplateCode", templateCode)
	params.Set("TemplateParam", paramString)
	params.Set("OutId", "")
	params.Set("Action", "SendSms")
	params.Set("PhoneNumbers", mobileNo)
	params.Set("Version", "2017-05-25")

	signstr := signHMAC(params, appSecret)
	params.Set("Signature", signstr)
	req, err := http.NewRequest(http.MethodGet, dyURL+"/?"+params.Encode(), nil)

	req.Header.Set("x-sdk-client", "Java/2.0.0")
	req.Header.Set("Accept", "application/json")
	req.Header.Set("User-Agent", "wl520")

	c := new(http.Client)
	resp, err := c.Do(req)

	if err != nil {
		return false, "", err
	}

	defer resp.Body.Close()
	bs, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return false, "", err
	}
	var result sendSmsResponse
	err = json.Unmarshal(bs, &result)
	if err != nil {
		return false, "", err
	}
	return result.Code == "OK", result.Message, nil
}
<commit_msg>Error handle<commit_after>/*
	目前使用阿里大于短信服务，本接口用于阿里大于迁移到阿里云通信后使用。
*/
package aldy

import (
	"crypto/hmac"
	"encoding/base64"

	"crypto/sha1"
	"encoding/json"

	"io/ioutil"

	"net/http"
	"net/url"
	"sort"
	"strings"
	"time"

	"github.com/satori/go.uuid"
)

// sendSmsResponse
type sendSmsResponse struct {
	Message   string
	RequestId string
	BizId     string
	Code      string
}

const (
	dyURL = "http://dysmsapi.aliyuncs.com"
)

// signHMAC 获取签名
func signHMAC(params url.Values, appSecret string) (signature string) {
	keys := []string{}
	for k := range params {
		keys = append(keys, k)
	}
	str := ""
	sort.Strings(keys)
	for _, k := range keys {
		str += "&" + url.QueryEscape(k) + "=" + url.QueryEscape(params.Get(k))
	}
	signstr := "GET&%2F&" + url.QueryEscape(str[1:])
	mac := hmac.New(sha1.New, []byte(appSecret+"&"))
	mac.Write([]byte(signstr))
	return base64.StdEncoding.EncodeToString(mac.Sum(nil))
}

// SendSMS
func SendSMS(mobileNo, signName, templateCode, paramString, appKey, appSecret string) (bool, string, error) {
	params := url.Values{}

	params.Set("Timestamp", time.Now().UTC().Format("2006-01-02T15:04:05Z"))
	params.Set("SignatureMethod", "HMAC-SHA1")
	params.Set("SignatureVersion", "1.0")
	uId := uuid.NewV4()
	params.Set("SignatureNonce", strings.ToLower(uId.String()))
	params.Set("AccessKeyId", appKey)
	params.Add("Format", "JSON")
	params.Set("RegionId", "cn-hangzhou")

	params.Set("SignName", signName)
	params.Set("TemplateCode", templateCode)
	params.Set("TemplateParam", paramString)
	params.Set("OutId", "")
	params.Set("Action", "SendSms")
	params.Set("PhoneNumbers", mobileNo)
	params.Set("Version", "2017-05-25")

	signstr := signHMAC(params, appSecret)
	params.Set("Signature", signstr)
	req, err := http.NewRequest(http.MethodGet, dyURL+"/?"+params.Encode(), nil)
	if err != nil {
		return false, "", err
	}

	req.Header.Set("x-sdk-client", "Java/2.0.0")
	req.Header.Set("Accept", "application/json")
	req.Header.Set("User-Agent", "wl520")

	c := new(http.Client)
	resp, err := c.Do(req)

	if err != nil {
		return false, "", err
	}

	defer resp.Body.Close()
	bs, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return false, "", err
	}
	var result sendSmsResponse
	err = json.Unmarshal(bs, &result)
	if err != nil {
		return false, "", err
	}
	return result.Code == "OK", result.Message, nil
}
<|endoftext|>


<commit_before>package ali

import (
	"crypto"
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"encoding/base64"
	"encoding/json"
	"encoding/pem"
	"fmt"
	"net/url"
	"reflect"
	"sort"
	"strings"
	"time"
)

func urlValues(c *Client, param PayParam) url.Values {
	values := url.Values{}
	values.Add("app_id", c.config.AppID)
	values.Add("method", param.URI())
	values.Add("format", "JSON")
	values.Add("charset", "utf-8")
	values.Add("sign_type", c.config.SignType)
	values.Add("timestamp", generateTimestampStr())
	values.Add("version", "1.0")
	values.Add("biz_content", param.BizContent())

	for k, v := range param.ExtraParams() {
		values.Add(k, v)
	}

	var keys []string
	for k := range values {
		keys = append(keys, k)
	}
	sort.Strings(keys)

	values.Add("sign", signature(keys, values, c.config.AppPrivateKey, c.config.SignType))
	return values
}

func signature(keys []string, values url.Values, privateKey []byte, signType string) string {
	if values == nil {
		values = url.Values{}
	}

	var valueList []string
	for _, k := range keys {
		v := strings.TrimSpace(values.Get(k))
		if v != "" {
			valueList = append(valueList, fmt.Sprintf("%s=%s", k, v))
		}
	}

	concat := strings.Join(valueList, "&")

	var sign string
	if signType == "RSA" {
		sign = signPKCS1v15([]byte(concat), privateKey, crypto.SHA1)
	} else if signType == "RSA2" {
		sign = signPKCS1v15([]byte(concat), privateKey, crypto.SHA256)
	}
	return sign
}

func signPKCS1v15(source, privateKey []byte, hash crypto.Hash) string {
	block, _ := pem.Decode(privateKey)
	if block == nil {
		fmt.Println("BLOCK", block, len(privateKey))
		return ""
	}

	rsaPrivateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
	// rsaPrivateKey, err := x509.ParsePKCS8PrivateKey(block.Bytes)
	if err != nil {
		fmt.Println("RSAPRIVATE", err)
		return ""
	}

	h := hash.New()
	h.Write(source)
	hashed := h.Sum(nil)

	s, err := rsa.SignPKCS1v15(rand.Reader, rsaPrivateKey, hash, hashed)
	// s, err := rsa.SignPKCS1v15(rand.Reader, rsaPrivateKey.(*rsa.PrivateKey), hash, hashed)
	if err != nil {
		fmt.Println("SIGNPKCS", err)
		return ""
	}
	return base64.StdEncoding.EncodeToString(s)
}

func verify(values url.Values, publicKey []byte, signType string) bool {
	var excluded []string
	for k := range values {
		if k == "sign" || k == "sign_type" {
			continue
		}
		excluded = append(excluded, k)
	}
	sort.Strings(excluded)

	var valueList []string
	for _, k := range excluded {
		v := values.Get(k)
		if v != "" {
			valueList = append(valueList, fmt.Sprintf("%s=%s", k, v))
		}
	}
	concat := strings.Join(valueList, "&")

	decoded, err := base64.StdEncoding.DecodeString(values.Get("sign"))
	if err != nil {
		return false
	}

	var ok bool
	if signType == "RSA" {
		ok = verifyPKCS1v15([]byte(concat), decoded, publicKey, crypto.SHA1)
	} else if signType == "RSA2" {
		ok = verifyPKCS1v15([]byte(concat), decoded, publicKey, crypto.SHA256)
	}
	return ok
}

func verifyPKCS1v15(source, sign, publicKey []byte, hash crypto.Hash) bool {
	h := hash.New()
	h.Write(source)
	hashed := h.Sum(nil)

	block, _ := pem.Decode(publicKey)
	if block == nil {
		fmt.Println("VERIFY BLOCK", block)
		return false
	}

	pub, err := x509.ParsePKIXPublicKey(block.Bytes)
	if err != nil {
		fmt.Println("ParsePKIXPublicKey", err)
		return false
	}

	rsaPublicKey := pub.(*rsa.PublicKey)
	err = rsa.VerifyPKCS1v15(rsaPublicKey, hash, hashed, sign)
	if err != nil {
		fmt.Println("VerifyPKCS1v15", err)
		return false
	}
	return true
}

func generateTimestampStr() string {
	now := time.Now()
	year, month, day := now.Date()
	hour, min, sec := now.Clock()
	return fmt.Sprintf("%d-%02d-%02d %02d:%02d:%02d", year, month, day, hour, min, sec)
}

func marshalJSON(val interface{}) string {
	data, err := json.Marshal(val)
	if err != nil {
		return ""
	}
	return string(data)
}

func toValues(st interface{}) (url.Values, error) {
	val := reflect.ValueOf(st)
	if val.Kind() == reflect.Ptr {
		val = val.Elem()
	}

	if val.Kind() != reflect.Struct {
		return nil, fmt.Errorf("need a struct type, got %T", st)
	}

	typ := val.Type()
	result := url.Values{}

	for i := 0; i < val.NumField(); i++ {
		sf := typ.Field(i)
		if tag, ok := sf.Tag.Lookup("json"); ok && tag != "" {
			result.Add(tag, val.Field(i).String())
		}
	}
	return result, nil
}
<commit_msg>add log<commit_after>package ali

import (
	"crypto"
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"encoding/base64"
	"encoding/json"
	"encoding/pem"
	"fmt"
	"net/url"
	"reflect"
	"sort"
	"strings"
	"time"
)

func urlValues(c *Client, param PayParam) url.Values {
	values := url.Values{}
	values.Add("app_id", c.config.AppID)
	values.Add("method", param.URI())
	values.Add("format", "JSON")
	values.Add("charset", "utf-8")
	values.Add("sign_type", c.config.SignType)
	values.Add("timestamp", generateTimestampStr())
	values.Add("version", "1.0")
	values.Add("biz_content", param.BizContent())

	for k, v := range param.ExtraParams() {
		values.Add(k, v)
	}

	var keys []string
	for k := range values {
		keys = append(keys, k)
	}
	sort.Strings(keys)

	values.Add("sign", signature(keys, values, c.config.AppPrivateKey, c.config.SignType))
	return values
}

func signature(keys []string, values url.Values, privateKey []byte, signType string) string {
	if values == nil {
		values = url.Values{}
	}

	var valueList []string
	for _, k := range keys {
		v := strings.TrimSpace(values.Get(k))
		if v != "" {
			valueList = append(valueList, fmt.Sprintf("%s=%s", k, v))
		}
	}

	concat := strings.Join(valueList, "&")

	var sign string
	if signType == "RSA" {
		sign = signPKCS1v15([]byte(concat), privateKey, crypto.SHA1)
	} else if signType == "RSA2" {
		sign = signPKCS1v15([]byte(concat), privateKey, crypto.SHA256)
	}
	return sign
}

func signPKCS1v15(source, privateKey []byte, hash crypto.Hash) string {
	block, _ := pem.Decode(privateKey)
	if block == nil {
		fmt.Println("BLOCK", block, len(privateKey))
		return ""
	}

	rsaPrivateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
	// rsaPrivateKey, err := x509.ParsePKCS8PrivateKey(block.Bytes)
	if err != nil {
		fmt.Println("RSAPRIVATE", err)
		return ""
	}

	h := hash.New()
	h.Write(source)
	hashed := h.Sum(nil)

	s, err := rsa.SignPKCS1v15(rand.Reader, rsaPrivateKey, hash, hashed)
	// s, err := rsa.SignPKCS1v15(rand.Reader, rsaPrivateKey.(*rsa.PrivateKey), hash, hashed)
	if err != nil {
		fmt.Println("SIGNPKCS", err)
		return ""
	}
	return base64.StdEncoding.EncodeToString(s)
}

func verify(values url.Values, publicKey []byte, signType string) bool {
	var excluded []string
	for k := range values {
		if k == "sign" || k == "sign_type" {
			continue
		}
		excluded = append(excluded, k)
	}
	sort.Strings(excluded)

	var valueList []string
	for _, k := range excluded {
		v := values.Get(k)
		if v != "" {
			valueList = append(valueList, fmt.Sprintf("%s=%s", k, v))
		}
	}
	concat := strings.Join(valueList, "&")

	decoded, err := base64.StdEncoding.DecodeString(values.Get("sign"))
	if err != nil {
		return false
	}

	fmt.Println("EXCLUDED", excluded)
	var ok bool
	if signType == "RSA" {
		ok = verifyPKCS1v15([]byte(concat), decoded, publicKey, crypto.SHA1)
	} else if signType == "RSA2" {
		ok = verifyPKCS1v15([]byte(concat), decoded, publicKey, crypto.SHA256)
	}
	return ok
}

func verifyPKCS1v15(source, sign, publicKey []byte, hash crypto.Hash) bool {
	h := hash.New()
	h.Write(source)
	hashed := h.Sum(nil)

	block, _ := pem.Decode(publicKey)
	if block == nil {
		fmt.Println("VERIFY BLOCK", block)
		return false
	}

	pub, err := x509.ParsePKIXPublicKey(block.Bytes)
	if err != nil {
		fmt.Println("ParsePKIXPublicKey", err)
		return false
	}

	rsaPublicKey := pub.(*rsa.PublicKey)
	err = rsa.VerifyPKCS1v15(rsaPublicKey, hash, hashed, sign)
	if err != nil {
		fmt.Println("VerifyPKCS1v15", err)
		return false
	}
	return true
}

func generateTimestampStr() string {
	now := time.Now()
	year, month, day := now.Date()
	hour, min, sec := now.Clock()
	return fmt.Sprintf("%d-%02d-%02d %02d:%02d:%02d", year, month, day, hour, min, sec)
}

func marshalJSON(val interface{}) string {
	data, err := json.Marshal(val)
	if err != nil {
		return ""
	}
	return string(data)
}

func toValues(st interface{}) (url.Values, error) {
	val := reflect.ValueOf(st)
	if val.Kind() == reflect.Ptr {
		val = val.Elem()
	}

	if val.Kind() != reflect.Struct {
		return nil, fmt.Errorf("need a struct type, got %T", st)
	}

	typ := val.Type()
	result := url.Values{}

	for i := 0; i < val.NumField(); i++ {
		sf := typ.Field(i)
		if tag, ok := sf.Tag.Lookup("json"); ok && tag != "" {
			result.Add(tag, val.Field(i).String())
		}
	}
	return result, nil
}
<|endoftext|>


<commit_before>package bitboard

import (
	"fmt"
	"github.com/sqdk/bitops"
)

const (
	WPawnId    = 0
	WRooksId   = 1
	WKnightsId = 2
	WBishopsId = 3
	WQueenId   = 4
	WKingId    = 5
	BPawnId    = 6
	BRooksId   = 7
	BKnightsId = 8
	BBishopsId = 9
	BQueenId   = 10
	BKingId    = 12
)

/*
	Each uint64 represents the board for a single piece type.
	Every bit indicates weather the given piece is at the specific location.

	Pieces can be moved by 0-based XY coordinate or by rank and file.

	The LookupTable is used to indicate if any piece is at the given location on the board
	This will shorten the time needed for a lot of operations and only increase memory overhead
 	by 1/13 of the total memory usage.

 	uint64 to board mapping:

	  1  2  3  4  5  6  7  8   <- Rank (coordinate y)
	a 0  1  2  3  4  5  6  7
	b 8  9  10 11 12 13 14 15
	c 16 17 18 19 20 21 22 23
	d 24 25 26 27 28 29 30 31
	e 32 33 34 35 36 37 38 39
	f 40 41 42 43 44 45 46 47
	g 48 49 50 51 52 53 54 55
	h 56 57 58 59 60 61 62 63
	^
	File (coordinate x)
*/
type BitBoard struct {
	Board       [13]uint64
	LookupTable uint64
}

func New() BitBoard {
	var board BitBoard
	board.Board[WPawnId] = uint64(4629771061636907072)
	board.Board[BPawnId] = uint64(144680345676153346)
	board.Board[WRooksId] = uint64(9223372036854775936)
	board.Board[BRooksId] = uint64(72057594037927937)
	board.Board[BKnightsId] = uint64(281474976710912)
	board.Board[WKnightsId] = uint64(36028797018996736)
	board.Board[WBishopsId] = uint64(140737496743936)
	board.Board[BBishopsId] = uint64(1099511693312)
	board.Board[WQueenId] = uint64(2147483648)
	board.Board[BQueenId] = uint64(4294967296)
	board.Board[WKingId] = uint64(549755813888)
	board.Board[BKingId] = uint64(16777216)
	board.LookupTable = uint64(0xFFFF00000000FFFF)
	return board
}

/*
	Moves piece by rank and file instead of XY. This is a lot slower because of the
	expensive operations needed to decipher the string input to XY coordinates.
	Intended use is for easy input of moves with standard chess notation.
*/
func (b *BitBoard) MovePieceFileRank(fileStart string, rankStart int, fileEnd string, rankEnd int) {
	xstart := rankToX(rankStart)
	xend := rankToX(rankEnd)
	ystart := fileToY(fileStart)
	yend := fileToY(fileEnd)
	b.MovePiece(xstart, ystart, xend, yend)
}

/*
	Returns the piece in the given file and rank as an integer
	indicating the type and color of the piece.
*/
func (b *BitBoard) GetPieceRowFile(file string, rank int) int {
	return b.GetPiece(rankToX(rank), fileToY(file))
}

func (b *BitBoard) MovePiece(xstart, ystart, xend, yend int) {
	piece := b.GetPiece(xstart, ystart)
	if piece == -1 {
		return
	}
	b.SetPiece(xend, yend, piece)
	b.RemovePieceFast(xstart, ystart, piece)
}

func (b *BitBoard) MovePieceFast(xstart, ystart, xend, yend, piece int) {
	b.SetPiece(xend, yend, piece)
	b.RemovePieceFast(xstart, ystart, piece)
}

func (b *BitBoard) GetPiece(x, y int) int {
	if x < 0 || y < 0 || x > 7 || y > 7 {
		return -2
	}

	//Query lookup table to check if there is a piece in the specific position
	if !bitops.QueryBit(&b.LookupTable, xyToIndex(y, x)) {
		return -1
	}

	for i := 0; i < 13; i++ {
		if bitops.QueryBit(&b.Board[i], xyToIndex(x, y)) {
			return i
		}
	}
	return -1
}

func (b *BitBoard) SetPiece(x, y, piece int) {
	bitops.SetBit(&b.Board[piece], xyToIndex(x, y), true)
	bitops.SetBit(&b.LookupTable, xyToIndex(y, x), true)
}

func (b *BitBoard) RemovePiece(x, y int) {
	for i := 0; i < 13; i++ {
		bitops.SetBit(&b.Board[i], xyToIndex(x, y), false)
	}
	bitops.SetBit(&b.LookupTable, xyToIndex(y, x), false)
}

func (b *BitBoard) RemovePieceFast(x, y, piece int) {
	bitops.SetBit(&b.Board[piece], xyToIndex(x, y), false)
	bitops.SetBit(&b.LookupTable, xyToIndex(y, x), false)
}

func xyToIndex(x, y int) int {
	return x + (y * 8)
}

func fileToY(file string) int {
	switch file {
	case "a":
		return 0
	case "b":
		return 1
	case "c":
		return 2
	case "d":
		return 3
	case "e":
		return 4
	case "f":
		return 5
	case "g":
		return 6
	case "h":
		return 7
	}
	return -1
}

func rankToX(rank int) int {
	return 8 - rank
}

func (b *BitBoard) PrettyPrint() {
	for x := 0; x < 8; x++ {
		for y := 0; y < 8; y++ {
			switch b.GetPiece(x, y) {
			case WPawnId:
				fmt.Print("P")
			case BPawnId:
				fmt.Print("p")
			case WRooksId:
				fmt.Print("R")
			case BRooksId:
				fmt.Print("r")
			case WKnightsId:
				fmt.Print("N")
			case BKnightsId:
				fmt.Print("n")
			case WBishopsId:
				fmt.Print("B")
			case BBishopsId:
				fmt.Print("b")
			case WKingId:
				fmt.Print("K")
			case BKingId:
				fmt.Print("k")
			case WQueenId:
				fmt.Print("Q")
			case BQueenId:
				fmt.Print("q")
			default:
				fmt.Print(".")
			}

		}
		fmt.Println()
	}
}

type XYPair struct {
	X int
	Y int
}
<commit_msg>MovePiece did not clean other piece indexes<commit_after>package bitboard

import (
	"fmt"
	"github.com/sqdk/bitops"
)

const (
	OUT_OF_BOUNDS = -2
	EMPTY_CELL    = -1
	WPawnId       = 0
	WRooksId      = 1
	WKnightsId    = 2
	WBishopsId    = 3
	WQueenId      = 4
	WKingId       = 5
	BPawnId       = 6
	BRooksId      = 7
	BKnightsId    = 8
	BBishopsId    = 9
	BQueenId      = 10
	BKingId       = 11
)

/*
	Each uint64 represents the board for a single piece type.
	Every bit indicates weather the given piece is at the specific location.

	Pieces can be moved by 0-based XY coordinate or by rank and file.

	The LookupTable is used to indicate if any piece is at the given location on the board
	This will shorten the time needed for a lot of operations and only increase memory overhead
 	by 1/13 of the total memory usage.

 	uint64 to board mapping:

	  1  2  3  4  5  6  7  8   <- Rank (coordinate y)
	a 0  1  2  3  4  5  6  7
	b 8  9  10 11 12 13 14 15
	c 16 17 18 19 20 21 22 23
	d 24 25 26 27 28 29 30 31
	e 32 33 34 35 36 37 38 39
	f 40 41 42 43 44 45 46 47
	g 48 49 50 51 52 53 54 55
	h 56 57 58 59 60 61 62 63
	^
	File (coordinate x)
*/
type BitBoard struct {
	Board       [12]uint64
	LookupTable uint64
}

/*
	Creates a new chess board by initializing the Board array
	with the appropriate values.
*/
func New() BitBoard {
	var board BitBoard
	board.Board[WPawnId] = uint64(4629771061636907072)
	board.Board[BPawnId] = uint64(144680345676153346)
	board.Board[WRooksId] = uint64(9223372036854775936)
	board.Board[BRooksId] = uint64(72057594037927937)
	board.Board[BKnightsId] = uint64(281474976710912)
	board.Board[WKnightsId] = uint64(36028797018996736)
	board.Board[WBishopsId] = uint64(140737496743936)
	board.Board[BBishopsId] = uint64(1099511693312)
	board.Board[WQueenId] = uint64(2147483648)
	board.Board[WKingId] = uint64(549755813888)
	board.Board[BKingId] = uint64(4294967296)
	board.Board[BQueenId] = uint64(16777216)

	board.LookupTable = uint64(0xFFFF00000000FFFF)
	return board
}

//Used to minimize memory overhead during test
func (board *BitBoard) ResetBoard() {
	board.Board[WPawnId] = uint64(4629771061636907072)
	board.Board[BPawnId] = uint64(144680345676153346)
	board.Board[WRooksId] = uint64(9223372036854775936)
	board.Board[BRooksId] = uint64(72057594037927937)
	board.Board[BKnightsId] = uint64(281474976710912)
	board.Board[WKnightsId] = uint64(36028797018996736)
	board.Board[WBishopsId] = uint64(140737496743936)
	board.Board[BBishopsId] = uint64(1099511693312)
	board.Board[WQueenId] = uint64(2147483648)
	board.Board[WKingId] = uint64(549755813888)
	board.Board[BKingId] = uint64(4294967296)
	board.Board[BQueenId] = uint64(16777216)

	board.LookupTable = uint64(0xFFFF00000000FFFF)
}

func Clone(b BitBoard) BitBoard {
	var board BitBoard
	for i := 0; i < len(b.Board); i++ {
		board.Board[i] = b.Board[i]
	}
	board.LookupTable = b.LookupTable
	return board
}

/*
	Moves piece by rank and file instead of XY. This is a lot slower because of the
	expensive operations needed to decipher the string input to XY coordinates.
	Intended use is for easy input of moves with standard chess notation.
*/
func (b *BitBoard) MovePieceFileRank(fileStart string, rankStart int, fileEnd string, rankEnd int) {
	xstart := RankToX(rankStart)
	xend := RankToX(rankEnd)
	ystart := FileToY(fileStart)
	yend := FileToY(fileEnd)
	b.MovePiece(xstart, ystart, xend, yend)
}

/*
	Returns the piece in the given file and rank as an integer
	indicating the type and color of the piece.
*/
func (b *BitBoard) GetPieceRowFile(file string, rank int) int {
	return b.GetPiece(RankToX(rank), FileToY(file))
}

func (b *BitBoard) MovePiece(xstart, ystart, xend, yend int) {
	piece := b.GetPiece(xstart, ystart)
	destinationPiece := b.GetPiece(xend, yend)
	if piece == EMPTY_CELL {
		return
	}
	if destinationPiece != EMPTY_CELL {
		b.RemovePieceFast(xend, yend, destinationPiece)
	}
	b.SetPiece(xend, yend, piece)
	b.RemovePieceFast(xstart, ystart, piece)
}

func (b *BitBoard) MovePieceFast(xstart, ystart, xend, yend, piece int) {
	b.SetPiece(xend, yend, piece)
	b.RemovePieceFast(xstart, ystart, piece)
}

func (b *BitBoard) GetPiece(x, y int) int {
	if x < 0 || y < 0 || x > 7 || y > 7 {
		return OUT_OF_BOUNDS
	}

	//Query lookup table to check if there is a piece in the specific position
	if !bitops.QueryBit(&b.LookupTable, xyToIndex(y, x)) {
		return EMPTY_CELL
	}

	for pieceIndex := 0; pieceIndex < 12; pieceIndex++ {
		if bitops.QueryBit(&b.Board[pieceIndex], xyToIndex(x, y)) {
			return pieceIndex
		}
	}
	return EMPTY_CELL
}

func (b *BitBoard) SetPiece(x, y, piece int) {
	bitops.SetBit(&b.Board[piece], xyToIndex(x, y), true)
	bitops.SetBit(&b.LookupTable, xyToIndex(y, x), true)
}

func (b *BitBoard) RemovePiece(x, y int) {
	piece := b.GetPiece(x, y)
	if piece == EMPTY_CELL {
		return
	}

	bitops.SetBit(&b.Board[piece], xyToIndex(x, y), false)
	bitops.SetBit(&b.LookupTable, xyToIndex(y, x), false)
}

func (b *BitBoard) RemovePieceFast(x, y, piece int) {
	bitops.SetBit(&b.Board[piece], xyToIndex(x, y), false)
	bitops.SetBit(&b.LookupTable, xyToIndex(y, x), false)
}

func xyToIndex(x, y int) int {
	return x + (y * 8)
}

func FileToY(file string) int {
	return int(file[0]) - 97
	/*
		switch file {
		case "a":
			return 0
		case "b":
			return 1
		case "c":
			return 2
		case "d":
			return 3
		case "e":
			return 4
		case "f":
			return 5
		case "g":
			return 6
		case "h":
			return 7
		}
		return -1*/
}

func YToFile(y int) string {
	return string(y + 97)
	/*
		if y <= 7 {
			return YToFileLookup[y]
		}
		return "?"*/
}

func RankToX(rank int) int {
	return 8 - rank
}

func XToRank(x int) int {
	return x + 1
}

func (b *BitBoard) PrettyPrint() {
	for x := 0; x < 8; x++ {
		for y := 0; y < 8; y++ {
			switch b.GetPiece(x, y) {
			case WPawnId:
				fmt.Print("P")
			case BPawnId:
				fmt.Print("p")
			case WRooksId:
				fmt.Print("R")
			case BRooksId:
				fmt.Print("r")
			case WKnightsId:
				fmt.Print("N")
			case BKnightsId:
				fmt.Print("n")
			case WBishopsId:
				fmt.Print("B")
			case BBishopsId:
				fmt.Print("b")
			case WKingId:
				fmt.Print("K")
			case BKingId:
				fmt.Print("k")
			case WQueenId:
				fmt.Print("Q")
			case BQueenId:
				fmt.Print("q")
			default:
				fmt.Print(".")
			}

		}
		fmt.Println()
	}
}

func (b *BitBoard) PrettyPrintMark(coords []XYPair) {
	fmt.Println(b.PrettyPrintMarkToString(coords))
}

func (b *BitBoard) PrettyPrintMarkToString(coords []XYPair) string {
	s := make([]byte, 0)
	for x := 0; x < 8; x++ {
		for y := 0; y < 8; y++ {
			piece := b.GetPiece(x, y)

			mark := false
			for i := 0; i < len(coords); i++ {
				if x == coords[i].X && y == coords[i].Y {
					if piece != -1 {
						s = append(s, '+')
					} else {
						s = append(s, '*')
					}
					mark = true
					break
				}
			}
			if mark {
				continue
			}

			switch piece {
			case WPawnId:
				s = append(s, 'P')
			case BPawnId:
				s = append(s, 'p')
			case WRooksId:
				s = append(s, 'R')
			case BRooksId:
				s = append(s, 'r')
			case WKnightsId:
				s = append(s, 'N')
			case BKnightsId:
				s = append(s, 'n')
			case WBishopsId:
				s = append(s, 'B')
			case BBishopsId:
				s = append(s, 'b')
			case WKingId:
				s = append(s, 'K')
			case BKingId:
				s = append(s, 'k')
			case WQueenId:
				s = append(s, 'Q')
			case BQueenId:
				s = append(s, 'q')
			default:
				s = append(s, '.')
			}
		}
		if x != 7 {
			s = append(s, '\n')
		}
	}
	return string(s)
}

type XYPair struct {
	X int
	Y int
}

func IsPieceWhite(piece int) bool {
	if piece >= WPawnId && piece < BPawnId {
		return true
	}
	return false
}
<|endoftext|>