<commit_before>package main

import (
	"net/http"
	"net/url"
	"regexp"
)

func serveStdlib() {
	http.HandleFunc("/ex", func(w http.ResponseWriter, r *http.Request) {
		r.ParseForm()

		target := r.Form.Get("target")
		// BAD: a request parameter is incorporated without validation into a URL redirect
		w.Header().Set("Location", target)
		w.WriteHeader(302)
	})

	http.HandleFunc("/ex1", func(w http.ResponseWriter, r *http.Request) {
		r.ParseForm()

		target := r.Form.Get("target")
		// Probably OK because the status is set to 500, but we catch it anyway
		w.Header().Set("Location", target)
		w.WriteHeader(500)
	})

	http.HandleFunc("/ex2", func(w http.ResponseWriter, r *http.Request) {
		r.ParseForm()

		target := r.Form.Get("target")
		// GOOD: local redirects are unproblematic
		w.Header().Set("Location", "/local"+target)
		// BAD: this could be a non-local redirect
		w.Header().Set("Location", "/"+target)
		// GOOD: localhost redirects are unproblematic
		w.Header().Set("Location", "//localhost/"+target)
		w.WriteHeader(302)
	})

	http.HandleFunc("/ex3", func(w http.ResponseWriter, r *http.Request) {
		r.ParseForm()

		target := r.Form.Get("target")
		// BAD: using the utility function
		http.Redirect(w, r, target, 301)
	})

	http.HandleFunc("/ex4", func(w http.ResponseWriter, r *http.Request) {
		r.ParseForm()

		target := r.Form.Get("target")
		// GOOD: comparison against known URLs
		if target == "semmle.com" {
			http.Redirect(w, r, target, 301)
		} else {
			w.WriteHeader(400)
		}
	})

	http.HandleFunc("/ex5", func(w http.ResponseWriter, r *http.Request) {
		r.ParseForm()

		target := r.Form.Get("target")
		me := "me"
		// BAD: may be a global redirection
		http.Redirect(w, r, target+"?from="+me, 301)
	})

	http.HandleFunc("/ex6", func(w http.ResponseWriter, r *http.Request) {
		r.ParseForm()

		target := r.Form.Get("target")
		// GOOD: request parameter is embedded in query string
		http.Redirect(w, r, someUrl()+"?target="+target, 301)
	})

	http.HandleFunc("/ex7", func(w http.ResponseWriter, r *http.Request) {
		r.ParseForm()

		target := r.Form.Get("target")
		// GOOD: request parameter is embedded in hash
		http.Redirect(w, r, someUrl()+(HASH+target), 302)
	})

	http.HandleFunc("/ex7", func(w http.ResponseWriter, r *http.Request) {
		r.ParseForm()

		target := r.Form.Get("target")
		target += "/index.html"
		// BAD
		http.Redirect(w, r, target, 302)
	})

	http.HandleFunc("/ex7", func(w http.ResponseWriter, r *http.Request) {
		r.ParseForm()

		target := r.Form.Get("target")
		// GOOD: request parameter is checked against a regexp
		if ok, _ := regexp.MatchString("", target); ok {
			http.Redirect(w, r, target, 302)
		} else {
			w.WriteHeader(400)
		}
	})

	http.HandleFunc("/ex8", func(w http.ResponseWriter, r *http.Request) {
		r.ParseForm()

		// GOOD: this only rewrites	the scheme, which is not dangerous as the host cannot change.
		if r.URL.Scheme == "http" {
			r.URL.Scheme = "https"
			http.Redirect(w, r, r.URL.String(), 302)
		} else {
			// ...
		}
	})

	http.HandleFunc("/ex8", func(w http.ResponseWriter, r *http.Request) {
		r.ParseForm()

		target := r.Form.Get("target")
		// GOOD: a check is done on the URL
		if isValidRedirect(target) {
			http.Redirect(w, r, target, 302)
		} else {
			// ...
		}
	})

	http.HandleFunc("/ex", func(w http.ResponseWriter, r *http.Request) {
		r.ParseForm()

		target := r.Form.Get("target")
		// GOOD: a check is done on the URL
		if isValidRedirect(target) {
			http.Redirect(w, r, target, 302)
		} else {
			// ...
		}
	})

	http.HandleFunc("/ex9", func(w http.ResponseWriter, r *http.Request) {
		r.ParseForm()

		target := r.Form.Get("target")
		// GOOD, but we catch this anyway: a check is done on the URL
		if !isValidRedirect(target) {
			target = "/"
		}

		http.Redirect(w, r, target, 302)
	})

	http.HandleFunc("/ex8", func(w http.ResponseWriter, r *http.Request) {
		r.ParseForm()

		// GOOD: Only safe parts of the URL are used
		url := *r.URL
		if url.Scheme == "http" {
			url.Scheme = "https"
			http.Redirect(w, r, url.String(), 302)
		} else {
			// ...
		}
	})

	http.HandleFunc("/ex8", func(w http.ResponseWriter, r *http.Request) {
		r.ParseForm()

		// GOOD: Only safe parts of the URL are used
		if r.URL.Scheme == "http" {
			http.Redirect(w, r, "https://"+r.URL.RequestURI(), 302)
		} else {
			// ...
		}
	})

	http.HandleFunc("/ex9", func(w http.ResponseWriter, r *http.Request) {
		r.ParseForm()

		target := r.FormValue("target")
		// BAD: a request parameter is incorporated without validation into a URL redirect
		http.Redirect(w, r, target, 301)
	})

	http.HandleFunc("/ex10", func(w http.ResponseWriter, r *http.Request) {
		r.ParseForm()

		target, _ := url.ParseRequestURI(r.FormValue("target"))
		// BAD: Path could start with `//`
		http.Redirect(w, r, target.Path, 301)
		// BAD: EscapedPath() does not help with that
		http.Redirect(w, r, target.EscapedPath(), 301)
	})

	http.ListenAndServe(":80", nil)
}
<commit_msg>Add tests for stdlib-http fields that aren't supposed to cause open-redirect alerts<commit_after>package main

import (
	"net/http"
	"net/url"
	"regexp"
)

func serveStdlib() {
	http.HandleFunc("/ex", func(w http.ResponseWriter, r *http.Request) {
		r.ParseForm()

		target := r.Form.Get("target")
		// BAD: a request parameter is incorporated without validation into a URL redirect
		w.Header().Set("Location", target)
		w.WriteHeader(302)
	})

	http.HandleFunc("/ex1", func(w http.ResponseWriter, r *http.Request) {
		r.ParseForm()

		target := r.Form.Get("target")
		// Probably OK because the status is set to 500, but we catch it anyway
		w.Header().Set("Location", target)
		w.WriteHeader(500)
	})

	http.HandleFunc("/ex2", func(w http.ResponseWriter, r *http.Request) {
		r.ParseForm()

		target := r.Form.Get("target")
		// GOOD: local redirects are unproblematic
		w.Header().Set("Location", "/local"+target)
		// BAD: this could be a non-local redirect
		w.Header().Set("Location", "/"+target)
		// GOOD: localhost redirects are unproblematic
		w.Header().Set("Location", "//localhost/"+target)
		w.WriteHeader(302)
	})

	http.HandleFunc("/ex3", func(w http.ResponseWriter, r *http.Request) {
		r.ParseForm()

		target := r.Form.Get("target")
		// BAD: using the utility function
		http.Redirect(w, r, target, 301)
	})

	http.HandleFunc("/ex4", func(w http.ResponseWriter, r *http.Request) {
		r.ParseForm()

		target := r.Form.Get("target")
		// GOOD: comparison against known URLs
		if target == "semmle.com" {
			http.Redirect(w, r, target, 301)
		} else {
			w.WriteHeader(400)
		}
	})

	http.HandleFunc("/ex5", func(w http.ResponseWriter, r *http.Request) {
		r.ParseForm()

		target := r.Form.Get("target")
		me := "me"
		// BAD: may be a global redirection
		http.Redirect(w, r, target+"?from="+me, 301)
	})

	http.HandleFunc("/ex6", func(w http.ResponseWriter, r *http.Request) {
		r.ParseForm()

		target := r.Form.Get("target")
		// GOOD: request parameter is embedded in query string
		http.Redirect(w, r, someUrl()+"?target="+target, 301)
	})

	http.HandleFunc("/ex7", func(w http.ResponseWriter, r *http.Request) {
		r.ParseForm()

		target := r.Form.Get("target")
		// GOOD: request parameter is embedded in hash
		http.Redirect(w, r, someUrl()+(HASH+target), 302)
	})

	http.HandleFunc("/ex7", func(w http.ResponseWriter, r *http.Request) {
		r.ParseForm()

		target := r.Form.Get("target")
		target += "/index.html"
		// BAD
		http.Redirect(w, r, target, 302)
	})

	http.HandleFunc("/ex7", func(w http.ResponseWriter, r *http.Request) {
		r.ParseForm()

		target := r.Form.Get("target")
		// GOOD: request parameter is checked against a regexp
		if ok, _ := regexp.MatchString("", target); ok {
			http.Redirect(w, r, target, 302)
		} else {
			w.WriteHeader(400)
		}
	})

	http.HandleFunc("/ex8", func(w http.ResponseWriter, r *http.Request) {
		r.ParseForm()

		// GOOD: this only rewrites	the scheme, which is not dangerous as the host cannot change.
		if r.URL.Scheme == "http" {
			r.URL.Scheme = "https"
			http.Redirect(w, r, r.URL.String(), 302)
		} else {
			// ...
		}
	})

	http.HandleFunc("/ex8", func(w http.ResponseWriter, r *http.Request) {
		r.ParseForm()

		target := r.Form.Get("target")
		// GOOD: a check is done on the URL
		if isValidRedirect(target) {
			http.Redirect(w, r, target, 302)
		} else {
			// ...
		}
	})

	http.HandleFunc("/ex", func(w http.ResponseWriter, r *http.Request) {
		r.ParseForm()

		target := r.Form.Get("target")
		// GOOD: a check is done on the URL
		if isValidRedirect(target) {
			http.Redirect(w, r, target, 302)
		} else {
			// ...
		}
	})

	http.HandleFunc("/ex9", func(w http.ResponseWriter, r *http.Request) {
		r.ParseForm()

		target := r.Form.Get("target")
		// GOOD, but we catch this anyway: a check is done on the URL
		if !isValidRedirect(target) {
			target = "/"
		}

		http.Redirect(w, r, target, 302)
	})

	http.HandleFunc("/ex8", func(w http.ResponseWriter, r *http.Request) {
		r.ParseForm()

		// GOOD: Only safe parts of the URL are used
		url := *r.URL
		if url.Scheme == "http" {
			url.Scheme = "https"
			http.Redirect(w, r, url.String(), 302)
		} else {
			// ...
		}
	})

	http.HandleFunc("/ex8", func(w http.ResponseWriter, r *http.Request) {
		r.ParseForm()

		// GOOD: Only safe parts of the URL are used
		if r.URL.Scheme == "http" {
			http.Redirect(w, r, "https://"+r.URL.RequestURI(), 302)
		} else {
			// ...
		}
	})

	http.HandleFunc("/ex9", func(w http.ResponseWriter, r *http.Request) {
		r.ParseForm()

		target := r.FormValue("target")
		// BAD: a request parameter is incorporated without validation into a URL redirect
		http.Redirect(w, r, target, 301)
	})

	http.HandleFunc("/ex10", func(w http.ResponseWriter, r *http.Request) {
		r.ParseForm()

		target, _ := url.ParseRequestURI(r.FormValue("target"))
		// BAD: Path could start with `//`
		http.Redirect(w, r, target.Path, 301)
		// BAD: EscapedPath() does not help with that
		http.Redirect(w, r, target.EscapedPath(), 301)
	})

	http.HandleFunc("/ex11", func(w http.ResponseWriter, r *http.Request) {
		// GOOD: all these fields and methods are disregarded for OpenRedirect attacks:
		buf := make([]byte, 100)
		r.Body.Read(buf)
		http.Redirect(w, r, string(buf), 301)
		bodyReader, _ := r.GetBody()
		bodyReader.Read(buf)
		http.Redirect(w, r, string(buf), 301)
		http.Redirect(w, r, r.PostForm["someField"][0], 301)
		http.Redirect(w, r, r.MultipartForm.Value["someField"][0], 301)
		http.Redirect(w, r, r.Header.Get("someField"), 301)
		http.Redirect(w, r, r.Trailer.Get("someField"), 301)
		http.Redirect(w, r, r.PostFormValue("someField"), 301)
		cookie, _ := r.Cookie("key")
		http.Redirect(w, r, cookie.Value, 301)
		http.Redirect(w, r, r.Cookies()[0].Value, 301)
		http.Redirect(w, r, r.Referer(), 301)
		http.Redirect(w, r, r.UserAgent(), 301)
		http.Redirect(w, r, r.PostFormValue("target"), 301)
		reader, _ := r.MultipartReader()
		part, _ := reader.NextPart()
		part.Read(buf)
		http.Redirect(w, r, string(buf), 301)
	})

	http.ListenAndServe(":80", nil)
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/conformal/btcscript"
	"github.com/conformal/btcutil"
	"github.com/conformal/btcwallet/tx"
	"github.com/conformal/btcwallet/wallet"
	"github.com/conformal/btcwire"
	"testing"
)

func TestFakeTxs(t *testing.T) {
	// First we need a wallet.
	w, err := wallet.NewWallet("banana wallet", "", []byte("banana"))
	if err != nil {
		t.Errorf("Can not create encrypted wallet: %s", err)
		return
	}
	btcw := &BtcWallet{
		Wallet: w,
	}

	w.Unlock([]byte("banana"))

	// Create and add a fake Utxo so we have some funds to spend.
	//
	// This will pass validation because btcscript is unaware of invalid
	// tx inputs, however, this example would fail in btcd.
	utxo := &tx.Utxo{}
	addr, err := w.NextUnusedAddress()
	if err != nil {
		t.Errorf("Cannot get next address: %s", err)
		return
	}
	addr160, _, err := btcutil.DecodeAddress(addr)
	if err != nil {
		t.Errorf("Cannot decode address: %s", err)
		return
	}
	copy(utxo.Addr[:], addr160)
	ophash := (btcwire.ShaHash)([...]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
		12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
		28, 29, 30, 31, 32})
	out := btcwire.NewOutPoint(&ophash, 0)
	utxo.Out = tx.OutPoint(*out)
	ss, err := btcscript.PayToPubKeyHashScript(addr160)
	if err != nil {
		t.Errorf("Could not create utxo PkScript: %s", err)
		return
	}
	utxo.Subscript = tx.PkScript(ss)
	utxo.Amt = 10000
	utxo.Height = 12345
	btcw.UtxoStore.s = append(btcw.UtxoStore.s, utxo)

	// Fake our current block height so btcd doesn't need to be queried.
	curHeight.h = 12346

	// Create the transaction.
	pairs := map[string]uint64{
		"17XhEvq9Nahdj7Xe1nv6oRe1tEmaHUuynH": 5000,
	}
	rawtx, err := btcw.txToPairs(pairs, 100, 0)
	if err != nil {
		t.Errorf("Tx creation failed: %s", err)
		return
	}
	_ = rawtx
}
<commit_msg>More test code<commit_after>package main

import (
	"encoding/hex"
	"encoding/json"
	"fmt"
	"github.com/conformal/btcjson"
	"github.com/conformal/btcscript"
	"github.com/conformal/btcutil"
	"github.com/conformal/btcwallet/tx"
	"github.com/conformal/btcwallet/wallet"
	"github.com/conformal/btcwire"
	"testing"
)

func TestFakeTxs(t *testing.T) {
	// First we need a wallet.
	w, err := wallet.NewWallet("banana wallet", "", []byte("banana"))
	if err != nil {
		t.Errorf("Can not create encrypted wallet: %s", err)
		return
	}
	btcw := &BtcWallet{
		Wallet: w,
	}

	w.Unlock([]byte("banana"))

	// Create and add a fake Utxo so we have some funds to spend.
	//
	// This will pass validation because btcscript is unaware of invalid
	// tx inputs, however, this example would fail in btcd.
	utxo := &tx.Utxo{}
	addr, err := w.NextUnusedAddress()
	if err != nil {
		t.Errorf("Cannot get next address: %s", err)
		return
	}
	addr160, _, err := btcutil.DecodeAddress(addr)
	if err != nil {
		t.Errorf("Cannot decode address: %s", err)
		return
	}
	copy(utxo.Addr[:], addr160)
	ophash := (btcwire.ShaHash)([...]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
		12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
		28, 29, 30, 31, 32})
	out := btcwire.NewOutPoint(&ophash, 0)
	utxo.Out = tx.OutPoint(*out)
	ss, err := btcscript.PayToPubKeyHashScript(addr160)
	if err != nil {
		t.Errorf("Could not create utxo PkScript: %s", err)
		return
	}
	utxo.Subscript = tx.PkScript(ss)
	utxo.Amt = 10000
	utxo.Height = 12345
	btcw.UtxoStore.s = append(btcw.UtxoStore.s, utxo)

	// Fake our current block height so btcd doesn't need to be queried.
	curHeight.h = 12346

	// Create the transaction.
	pairs := map[string]uint64{
		"17XhEvq9Nahdj7Xe1nv6oRe1tEmaHUuynH": 5000,
	}
	rawtx, err := btcw.txToPairs(pairs, 100, 0)
	if err != nil {
		t.Errorf("Tx creation failed: %s", err)
		return
	}

	msg := btcjson.Message{
		Jsonrpc: "1.0",
		Id:      "test",
		Method:  "sendrawtransaction",
		Params: []interface{}{
			hex.EncodeToString(rawtx),
		},
	}
	m, _ := json.Marshal(msg)
	_ = m
	_ = fmt.Println

	// Uncomment to print out json to send raw transaction
	// fmt.Println(string(m))
}
<|endoftext|>


<commit_before>package runner

import (
	"os"
	"os/exec"

	st "github.com/dyweb/Ayi/common/structure"
	"github.com/kballard/go-shellquote"
	"github.com/pkg/errors"
)

// commands that should be called using shell,
// because mostly they would be expecting shell expansion on parameters
var shellCommands = st.NewSet("rm", "cp", "mv", "mkdir", "tar")

// NewCmd can properly split the executable with its arguments
// TODO: may need to add a context to handle things like using shell or not
func NewCmd(cmdStr string) (*exec.Cmd, error) {
	segments, err := shellquote.Split(cmdStr)
	if err != nil {
		return nil, errors.Wrap(err, "can't parse command")
	}
	return exec.Command(segments[0], segments[1:]...), nil
}

// NewCmdWithAutoShell automatically use `sh -c` syntax for a small list of executable
// because most people expect shell expansion i.e. wild chars when using them
// TODO: test if it really works, current unit test just test the number of arguments
func NewCmdWithAutoShell(cmdStr string) (*exec.Cmd, error) {
	segments, err := shellquote.Split(cmdStr)
	if err != nil {
		return nil, errors.Wrap(err, "can't parse command")
	}
	name := segments[0]
	useShell := shellCommands.Contains(name)
	if useShell {
		// TODO: may use shellquote join?
		// NOTE: http://stackoverflow.com/questions/18946837/go-variadic-function-and-too-many-arguments
		// the `append` here is a must "sh", "-c", segments[1:]... won't work
		return exec.Command("sh", append([]string{"-c"}, segments[1:]...)...), nil
	}
	return exec.Command(segments[0], segments[1:]...), nil
}

func RunCommand(cmdStr string) error {
	cmd, err := NewCmd(cmdStr)
	if err != nil {
		return errors.Wrap(err, "can't create cmd from command string")
	}
	// TODO: dry run, maybe add a context
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	err = cmd.Run()
	if err != nil {
		return errors.Wrap(err, "failure when executing command")
	}
	return nil
}
<commit_msg>[common][runner] Add echo to shell list<commit_after>package runner

import (
	"os"
	"os/exec"

	st "github.com/dyweb/Ayi/common/structure"
	"github.com/kballard/go-shellquote"
	"github.com/pkg/errors"
)

// commands that should be called using shell,
// because mostly they would be expecting shell expansion on parameters
var shellCommands = st.NewSet("echo", "rm", "cp", "mv", "mkdir", "tar")

// NewCmd can properly split the executable with its arguments
// TODO: may need to add a context to handle things like using shell or not
func NewCmd(cmdStr string) (*exec.Cmd, error) {
	segments, err := shellquote.Split(cmdStr)
	if err != nil {
		return nil, errors.Wrap(err, "can't parse command")
	}
	return exec.Command(segments[0], segments[1:]...), nil
}

// NewCmdWithAutoShell automatically use `sh -c` syntax for a small list of executable
// because most people expect shell expansion i.e. wild chars when using them
// TODO: test if it really works, current unit test just test the number of arguments
func NewCmdWithAutoShell(cmdStr string) (*exec.Cmd, error) {
	segments, err := shellquote.Split(cmdStr)
	if err != nil {
		return nil, errors.Wrap(err, "can't parse command")
	}
	name := segments[0]
	useShell := shellCommands.Contains(name)
	if useShell {
		// TODO: may use shellquote join?
		// NOTE: http://stackoverflow.com/questions/18946837/go-variadic-function-and-too-many-arguments
		// the `append` here is a must "sh", "-c", segments[1:]... won't work
		return exec.Command("sh", append([]string{"-c"}, segments[1:]...)...), nil
	}
	return exec.Command(segments[0], segments[1:]...), nil
}

func RunCommand(cmdStr string) error {
	cmd, err := NewCmd(cmdStr)
	if err != nil {
		return errors.Wrap(err, "can't create cmd from command string")
	}
	// TODO: dry run, maybe add a context
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	err = cmd.Run()
	if err != nil {
		return errors.Wrap(err, "failure when executing command")
	}
	return nil
}
<|endoftext|>


<commit_before>package cc_messages

type LRPInstanceState string

const (
	LRPInstanceStateStarting LRPInstanceState = "STARTING"
	LRPInstanceStateRunning  LRPInstanceState = "RUNNING"
	LRPInstanceStateCrashed  LRPInstanceState = "CRASHED"
	LRPInstanceStateUnknown  LRPInstanceState = "UNKNOWN"
)

type LRPInstance struct {
	ProcessGuid  string            `json:"process_guid"`
	InstanceGuid string            `json:"instance_guid"`
	Index        uint              `json:"index"`
	State        LRPInstanceState  `json:"state"`
	Details      string            `json:"details,omitempty"`
	Since        int64             `json:"since_in_ns"`
	Stats        *LRPInstanceStats `json:"stats,omitempty"`
}

type LRPInstanceStats struct {
	CpuPercentage float64 `json:"cpu"`
	MemoryBytes   uint64  `json:"mem"`
	DiskBytes     uint64  `json:"disk"`
}
<commit_msg>Add new fields to match DEA<commit_after>package cc_messages

import "time"

type LRPInstanceState string

const (
	LRPInstanceStateStarting LRPInstanceState = "STARTING"
	LRPInstanceStateRunning  LRPInstanceState = "RUNNING"
	LRPInstanceStateCrashed  LRPInstanceState = "CRASHED"
	LRPInstanceStateUnknown  LRPInstanceState = "UNKNOWN"
)

type LRPInstance struct {
	ProcessGuid  string            `json:"process_guid"`
	InstanceGuid string            `json:"instance_guid"`
	Index        uint              `json:"index"`
	State        LRPInstanceState  `json:"state"`
	Details      string            `json:"details,omitempty"`
	Host         string            `json:"host,omitempty"`
	Port         uint16            `json:"port,omitempty"`
	Since        int64             `json:"since"`
	Stats        *LRPInstanceStats `json:"stats,omitempty"`
}

type LRPInstanceStats struct {
	Time          time.Time `json:"time"`
	CpuPercentage float64   `json:"cpu"`
	MemoryBytes   uint64    `json:"mem"`
	DiskBytes     uint64    `json:"disk"`
}
<|endoftext|>


<commit_before>// Copyright 2012 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// 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 s3

import (
	"bytes"
	"crypto/md5"
	"encoding/base64"
	"errors"
	"github.com/jacobsa/aws/s3/auth/mock"
	"github.com/jacobsa/aws/s3/http"
	"github.com/jacobsa/aws/s3/http/mock"
	. "github.com/jacobsa/oglematchers"
	"github.com/jacobsa/oglemock"
	. "github.com/jacobsa/ogletest"
	"strings"
	"testing"
	"time"
)

func TestBucket(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

func computeBase64Md5(d []byte) string {
	h := md5.New()
	if _, err := h.Write(d); err != nil {
		panic(err)
	}

	buf := new(bytes.Buffer)
	e := base64.NewEncoder(base64.StdEncoding, buf)
	if _, err := e.Write(h.Sum(nil)); err != nil {
		panic(err)
	}

	e.Close()
	return buf.String()
}

type fakeClock struct {
	now time.Time
}

func (c *fakeClock) Now() time.Time {
	return c.now
}

type bucketTest struct {
	httpConn mock_http.MockConn
	signer   mock_auth.MockSigner
	bucket   Bucket
	clock    *fakeClock
}

func (t *bucketTest) SetUp(i *TestInfo) {
	var err error

	t.httpConn = mock_http.NewMockConn(i.MockController, "httpConn")
	t.signer = mock_auth.NewMockSigner(i.MockController, "signer")
	t.clock = &fakeClock{}

	t.bucket, err = openBucket("some.bucket", t.httpConn, t.signer, t.clock)
	AssertEq(nil, err)
}

////////////////////////////////////////////////////////////////////////
// GetObject
////////////////////////////////////////////////////////////////////////

type GetObjectTest struct {
	bucketTest
}

func init() { RegisterTestSuite(&GetObjectTest{}) }

func (t *GetObjectTest) KeyNotValidUtf8() {
	key := "\x80\x81\x82"

	// Call
	_, err := t.bucket.GetObject(key)

	ExpectThat(err, Error(HasSubstr("valid")))
	ExpectThat(err, Error(HasSubstr("UTF-8")))
}

func (t *GetObjectTest) KeyTooLong() {
	key := strings.Repeat("a", 1025)

	// Call
	_, err := t.bucket.GetObject(key)

	ExpectThat(err, Error(HasSubstr("1024")))
	ExpectThat(err, Error(HasSubstr("bytes")))
}

func (t *GetObjectTest) KeyContainsNullByte() {
	key := "taco\x00burrito"

	// Call
	_, err := t.bucket.GetObject(key)

	ExpectThat(err, Error(HasSubstr("null")))
}

func (t *GetObjectTest) KeyIsEmpty() {
	key := ""

	// Call
	_, err := t.bucket.GetObject(key)

	ExpectThat(err, Error(HasSubstr("empty")))
}

func (t *GetObjectTest) CallsSigner() {
	key := "foo/bar/baz"

	// Clock
	t.clock.now = time.Date(1985, time.March, 18, 15, 33, 17, 123, time.UTC)

	// Signer
	var httpReq *http.Request
	ExpectCall(t.signer, "Sign")(Any()).
		WillOnce(oglemock.Invoke(func(r *http.Request) error {
		httpReq = r
		return errors.New("")
	}))

	// Call
	t.bucket.GetObject(key)

	AssertNe(nil, httpReq)
	ExpectEq("GET", httpReq.Verb)
	ExpectEq("/some.bucket/foo/bar/baz", httpReq.Path)
	ExpectEq("Mon, 18 Mar 1985 15:33:17 UTC", httpReq.Headers["Date"])
}

func (t *GetObjectTest) SignerReturnsError() {
	key := "a"

	// Signer
	ExpectCall(t.signer, "Sign")(Any()).
		WillOnce(oglemock.Return(errors.New("taco")))

	// Call
	_, err := t.bucket.GetObject(key)

	ExpectThat(err, Error(HasSubstr("Sign")))
	ExpectThat(err, Error(HasSubstr("taco")))
}

func (t *GetObjectTest) CallsConn() {
	key := "a"

	// Signer
	ExpectCall(t.signer, "Sign")(Any()).
		WillOnce(oglemock.Invoke(func(r *http.Request) error {
		r.Verb = "burrito"
		return nil
	}))

	// Conn
	var httpReq *http.Request
	ExpectCall(t.httpConn, "SendRequest")(Any()).
		WillOnce(oglemock.Invoke(func(r *http.Request) (*http.Response, error) {
		httpReq = r
		return nil, errors.New("")
	}))

	// Call
	t.bucket.GetObject(key)

	AssertNe(nil, httpReq)
	ExpectEq("burrito", httpReq.Verb)
}

func (t *GetObjectTest) ConnReturnsError() {
	key := "a"

	// Signer
	ExpectCall(t.signer, "Sign")(Any()).
		WillOnce(oglemock.Return(nil))

	// Conn
	ExpectCall(t.httpConn, "SendRequest")(Any()).
		WillOnce(oglemock.Return(nil, errors.New("taco")))

	// Call
	_, err := t.bucket.GetObject(key)

	ExpectThat(err, Error(HasSubstr("SendRequest")))
	ExpectThat(err, Error(HasSubstr("taco")))
}

func (t *GetObjectTest) ServerReturnsError() {
	key := "a"

	// Signer
	ExpectCall(t.signer, "Sign")(Any()).
		WillOnce(oglemock.Return(nil))

	// Conn
	resp := &http.Response{
		StatusCode: 500,
		Body:       []byte("taco"),
	}

	ExpectCall(t.httpConn, "SendRequest")(Any()).
		WillOnce(oglemock.Return(resp, nil))

	// Call
	_, err := t.bucket.GetObject(key)

	ExpectThat(err, Error(HasSubstr("server")))
	ExpectThat(err, Error(HasSubstr("500")))
	ExpectThat(err, Error(HasSubstr("taco")))
}

func (t *GetObjectTest) ReturnsResponseBody() {
	key := "a"

	// Signer
	ExpectCall(t.signer, "Sign")(Any()).
		WillOnce(oglemock.Return(nil))

	// Conn
	resp := &http.Response{
		StatusCode: 200,
		Body:       []byte("taco"),
	}

	ExpectCall(t.httpConn, "SendRequest")(Any()).
		WillOnce(oglemock.Return(resp, nil))

	// Call
	data, err := t.bucket.GetObject(key)
	AssertEq(nil, err)

	ExpectThat(data, DeepEquals([]byte("taco")))
}

////////////////////////////////////////////////////////////////////////
// StoreObject
////////////////////////////////////////////////////////////////////////

type StoreObjectTest struct {
	bucketTest
}

func init() { RegisterTestSuite(&StoreObjectTest{}) }

func (t *StoreObjectTest) KeyNotValidUtf8() {
	key := "\x80\x81\x82"
	data := []byte{}

	// Call
	err := t.bucket.StoreObject(key, data)

	ExpectThat(err, Error(HasSubstr("valid")))
	ExpectThat(err, Error(HasSubstr("UTF-8")))
}

func (t *StoreObjectTest) KeyTooLong() {
	key := strings.Repeat("a", 1025)
	data := []byte{}

	// Call
	err := t.bucket.StoreObject(key, data)

	ExpectThat(err, Error(HasSubstr("1024")))
	ExpectThat(err, Error(HasSubstr("bytes")))
}

func (t *StoreObjectTest) KeyContainsNullByte() {
	key := "taco\x00burrito"
	data := []byte{}

	// Call
	err := t.bucket.StoreObject(key, data)

	ExpectThat(err, Error(HasSubstr("null")))
}

func (t *StoreObjectTest) KeyIsEmpty() {
	key := ""
	data := []byte{}

	// Call
	err := t.bucket.StoreObject(key, data)

	ExpectThat(err, Error(HasSubstr("empty")))
}

func (t *StoreObjectTest) CallsSigner() {
	key := "foo/bar/baz"
	data := []byte{0x00, 0xde, 0xad, 0xbe, 0xef}

	// Clock
	t.clock.now = time.Date(1985, time.March, 18, 15, 33, 17, 123, time.UTC)

	// Signer
	var httpReq *http.Request
	ExpectCall(t.signer, "Sign")(Any()).
		WillOnce(oglemock.Invoke(func(r *http.Request) error {
		httpReq = r
		return errors.New("")
	}))

	// Call
	t.bucket.StoreObject(key, data)

	AssertNe(nil, httpReq)
	ExpectEq("PUT", httpReq.Verb)
	ExpectEq("/some.bucket/foo/bar/baz", httpReq.Path)
	ExpectEq("Mon, 18 Mar 1985 15:33:17 UTC", httpReq.Headers["Date"])
	ExpectEq(computeBase64Md5(data), httpReq.Headers["Content-MD5"])
	ExpectThat(httpReq.Body, DeepEquals(data))
}

func (t *StoreObjectTest) SignerReturnsError() {
	key := "a"
	data := []byte{}

	// Signer
	ExpectCall(t.signer, "Sign")(Any()).
		WillOnce(oglemock.Return(errors.New("taco")))

	// Call
	err := t.bucket.StoreObject(key, data)

	ExpectThat(err, Error(HasSubstr("Sign")))
	ExpectThat(err, Error(HasSubstr("taco")))
}

func (t *StoreObjectTest) CallsConn() {
	key := "a"
	data := []byte{}

	// Signer
	ExpectCall(t.signer, "Sign")(Any()).
		WillOnce(oglemock.Invoke(func(r *http.Request) error {
		r.Verb = "burrito"
		return nil
	}))

	// Conn
	var httpReq *http.Request
	ExpectCall(t.httpConn, "SendRequest")(Any()).
		WillOnce(oglemock.Invoke(func(r *http.Request) (*http.Response, error) {
		httpReq = r
		return nil, errors.New("")
	}))

	// Call
	t.bucket.StoreObject(key, data)

	AssertNe(nil, httpReq)
	ExpectEq("burrito", httpReq.Verb)
}

func (t *StoreObjectTest) ConnReturnsError() {
	key := "a"
	data := []byte{}

	// Signer
	ExpectCall(t.signer, "Sign")(Any()).
		WillOnce(oglemock.Return(nil))

	// Conn
	ExpectCall(t.httpConn, "SendRequest")(Any()).
		WillOnce(oglemock.Return(nil, errors.New("taco")))

	// Call
	err := t.bucket.StoreObject(key, data)

	ExpectThat(err, Error(HasSubstr("SendRequest")))
	ExpectThat(err, Error(HasSubstr("taco")))
}

func (t *StoreObjectTest) ServerReturnsError() {
	key := "a"
	data := []byte{}

	// Signer
	ExpectCall(t.signer, "Sign")(Any()).
		WillOnce(oglemock.Return(nil))

	// Conn
	resp := &http.Response{
		StatusCode: 500,
		Body:       []byte("taco"),
	}

	ExpectCall(t.httpConn, "SendRequest")(Any()).
		WillOnce(oglemock.Return(resp, nil))

	// Call
	err := t.bucket.StoreObject(key, data)

	ExpectThat(err, Error(HasSubstr("server")))
	ExpectThat(err, Error(HasSubstr("500")))
	ExpectThat(err, Error(HasSubstr("taco")))
}

func (t *StoreObjectTest) ServerSaysOkay() {
	key := "a"
	data := []byte{}

	// Signer
	ExpectCall(t.signer, "Sign")(Any()).
		WillOnce(oglemock.Return(nil))

	// Conn
	resp := &http.Response{
		StatusCode: 200,
		Body:       []byte("taco"),
	}

	ExpectCall(t.httpConn, "SendRequest")(Any()).
		WillOnce(oglemock.Return(resp, nil))

	// Call
	err := t.bucket.StoreObject(key, data)

	ExpectEq(nil, err)
}

////////////////////////////////////////////////////////////////////////
// ListKeys
////////////////////////////////////////////////////////////////////////

type ListKeysTest struct {
	bucketTest
}

func init() { RegisterTestSuite(&ListKeysTest{}) }

func (t *ListKeysTest) CallsSignerWithEmptyMin() {
	ExpectFalse(true, "TODO")
}

func (t *ListKeysTest) CallsSignerWithNonEmptyMin() {
	ExpectFalse(true, "TODO")
}

func (t *ListKeysTest) SignerReturnsError() {
	ExpectFalse(true, "TODO")
}

func (t *ListKeysTest) CallsConn() {
	ExpectFalse(true, "TODO")
}

func (t *ListKeysTest) ConnReturnsError() {
	ExpectFalse(true, "TODO")
}

func (t *ListKeysTest) ServerReturnsError() {
	ExpectFalse(true, "TODO")
}

func (t *ListKeysTest) ResponseBodyIsJunk() {
	ExpectFalse(true, "TODO")
}

func (t *ListKeysTest) ResponseContainsNoKeys() {
	ExpectFalse(true, "TODO")
}

func (t *ListKeysTest) ResponseContainsSomeKeys() {
	ExpectFalse(true, "TODO")
}
<commit_msg>ListKeysTest.CallsSignerWithEmptyMin<commit_after>// Copyright 2012 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// 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 s3

import (
	"bytes"
	"crypto/md5"
	"encoding/base64"
	"errors"
	"github.com/jacobsa/aws/s3/auth/mock"
	"github.com/jacobsa/aws/s3/http"
	"github.com/jacobsa/aws/s3/http/mock"
	. "github.com/jacobsa/oglematchers"
	"github.com/jacobsa/oglemock"
	. "github.com/jacobsa/ogletest"
	"strings"
	"testing"
	"time"
)

func TestBucket(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

func computeBase64Md5(d []byte) string {
	h := md5.New()
	if _, err := h.Write(d); err != nil {
		panic(err)
	}

	buf := new(bytes.Buffer)
	e := base64.NewEncoder(base64.StdEncoding, buf)
	if _, err := e.Write(h.Sum(nil)); err != nil {
		panic(err)
	}

	e.Close()
	return buf.String()
}

type fakeClock struct {
	now time.Time
}

func (c *fakeClock) Now() time.Time {
	return c.now
}

type bucketTest struct {
	httpConn mock_http.MockConn
	signer   mock_auth.MockSigner
	bucket   Bucket
	clock    *fakeClock
}

func (t *bucketTest) SetUp(i *TestInfo) {
	var err error

	t.httpConn = mock_http.NewMockConn(i.MockController, "httpConn")
	t.signer = mock_auth.NewMockSigner(i.MockController, "signer")
	t.clock = &fakeClock{}

	t.bucket, err = openBucket("some.bucket", t.httpConn, t.signer, t.clock)
	AssertEq(nil, err)
}

////////////////////////////////////////////////////////////////////////
// GetObject
////////////////////////////////////////////////////////////////////////

type GetObjectTest struct {
	bucketTest
}

func init() { RegisterTestSuite(&GetObjectTest{}) }

func (t *GetObjectTest) KeyNotValidUtf8() {
	key := "\x80\x81\x82"

	// Call
	_, err := t.bucket.GetObject(key)

	ExpectThat(err, Error(HasSubstr("valid")))
	ExpectThat(err, Error(HasSubstr("UTF-8")))
}

func (t *GetObjectTest) KeyTooLong() {
	key := strings.Repeat("a", 1025)

	// Call
	_, err := t.bucket.GetObject(key)

	ExpectThat(err, Error(HasSubstr("1024")))
	ExpectThat(err, Error(HasSubstr("bytes")))
}

func (t *GetObjectTest) KeyContainsNullByte() {
	key := "taco\x00burrito"

	// Call
	_, err := t.bucket.GetObject(key)

	ExpectThat(err, Error(HasSubstr("null")))
}

func (t *GetObjectTest) KeyIsEmpty() {
	key := ""

	// Call
	_, err := t.bucket.GetObject(key)

	ExpectThat(err, Error(HasSubstr("empty")))
}

func (t *GetObjectTest) CallsSigner() {
	key := "foo/bar/baz"

	// Clock
	t.clock.now = time.Date(1985, time.March, 18, 15, 33, 17, 123, time.UTC)

	// Signer
	var httpReq *http.Request
	ExpectCall(t.signer, "Sign")(Any()).
		WillOnce(oglemock.Invoke(func(r *http.Request) error {
		httpReq = r
		return errors.New("")
	}))

	// Call
	t.bucket.GetObject(key)

	AssertNe(nil, httpReq)
	ExpectEq("GET", httpReq.Verb)
	ExpectEq("/some.bucket/foo/bar/baz", httpReq.Path)
	ExpectEq("Mon, 18 Mar 1985 15:33:17 UTC", httpReq.Headers["Date"])
}

func (t *GetObjectTest) SignerReturnsError() {
	key := "a"

	// Signer
	ExpectCall(t.signer, "Sign")(Any()).
		WillOnce(oglemock.Return(errors.New("taco")))

	// Call
	_, err := t.bucket.GetObject(key)

	ExpectThat(err, Error(HasSubstr("Sign")))
	ExpectThat(err, Error(HasSubstr("taco")))
}

func (t *GetObjectTest) CallsConn() {
	key := "a"

	// Signer
	ExpectCall(t.signer, "Sign")(Any()).
		WillOnce(oglemock.Invoke(func(r *http.Request) error {
		r.Verb = "burrito"
		return nil
	}))

	// Conn
	var httpReq *http.Request
	ExpectCall(t.httpConn, "SendRequest")(Any()).
		WillOnce(oglemock.Invoke(func(r *http.Request) (*http.Response, error) {
		httpReq = r
		return nil, errors.New("")
	}))

	// Call
	t.bucket.GetObject(key)

	AssertNe(nil, httpReq)
	ExpectEq("burrito", httpReq.Verb)
}

func (t *GetObjectTest) ConnReturnsError() {
	key := "a"

	// Signer
	ExpectCall(t.signer, "Sign")(Any()).
		WillOnce(oglemock.Return(nil))

	// Conn
	ExpectCall(t.httpConn, "SendRequest")(Any()).
		WillOnce(oglemock.Return(nil, errors.New("taco")))

	// Call
	_, err := t.bucket.GetObject(key)

	ExpectThat(err, Error(HasSubstr("SendRequest")))
	ExpectThat(err, Error(HasSubstr("taco")))
}

func (t *GetObjectTest) ServerReturnsError() {
	key := "a"

	// Signer
	ExpectCall(t.signer, "Sign")(Any()).
		WillOnce(oglemock.Return(nil))

	// Conn
	resp := &http.Response{
		StatusCode: 500,
		Body:       []byte("taco"),
	}

	ExpectCall(t.httpConn, "SendRequest")(Any()).
		WillOnce(oglemock.Return(resp, nil))

	// Call
	_, err := t.bucket.GetObject(key)

	ExpectThat(err, Error(HasSubstr("server")))
	ExpectThat(err, Error(HasSubstr("500")))
	ExpectThat(err, Error(HasSubstr("taco")))
}

func (t *GetObjectTest) ReturnsResponseBody() {
	key := "a"

	// Signer
	ExpectCall(t.signer, "Sign")(Any()).
		WillOnce(oglemock.Return(nil))

	// Conn
	resp := &http.Response{
		StatusCode: 200,
		Body:       []byte("taco"),
	}

	ExpectCall(t.httpConn, "SendRequest")(Any()).
		WillOnce(oglemock.Return(resp, nil))

	// Call
	data, err := t.bucket.GetObject(key)
	AssertEq(nil, err)

	ExpectThat(data, DeepEquals([]byte("taco")))
}

////////////////////////////////////////////////////////////////////////
// StoreObject
////////////////////////////////////////////////////////////////////////

type StoreObjectTest struct {
	bucketTest
}

func init() { RegisterTestSuite(&StoreObjectTest{}) }

func (t *StoreObjectTest) KeyNotValidUtf8() {
	key := "\x80\x81\x82"
	data := []byte{}

	// Call
	err := t.bucket.StoreObject(key, data)

	ExpectThat(err, Error(HasSubstr("valid")))
	ExpectThat(err, Error(HasSubstr("UTF-8")))
}

func (t *StoreObjectTest) KeyTooLong() {
	key := strings.Repeat("a", 1025)
	data := []byte{}

	// Call
	err := t.bucket.StoreObject(key, data)

	ExpectThat(err, Error(HasSubstr("1024")))
	ExpectThat(err, Error(HasSubstr("bytes")))
}

func (t *StoreObjectTest) KeyContainsNullByte() {
	key := "taco\x00burrito"
	data := []byte{}

	// Call
	err := t.bucket.StoreObject(key, data)

	ExpectThat(err, Error(HasSubstr("null")))
}

func (t *StoreObjectTest) KeyIsEmpty() {
	key := ""
	data := []byte{}

	// Call
	err := t.bucket.StoreObject(key, data)

	ExpectThat(err, Error(HasSubstr("empty")))
}

func (t *StoreObjectTest) CallsSigner() {
	key := "foo/bar/baz"
	data := []byte{0x00, 0xde, 0xad, 0xbe, 0xef}

	// Clock
	t.clock.now = time.Date(1985, time.March, 18, 15, 33, 17, 123, time.UTC)

	// Signer
	var httpReq *http.Request
	ExpectCall(t.signer, "Sign")(Any()).
		WillOnce(oglemock.Invoke(func(r *http.Request) error {
		httpReq = r
		return errors.New("")
	}))

	// Call
	t.bucket.StoreObject(key, data)

	AssertNe(nil, httpReq)
	ExpectEq("PUT", httpReq.Verb)
	ExpectEq("/some.bucket/foo/bar/baz", httpReq.Path)
	ExpectEq("Mon, 18 Mar 1985 15:33:17 UTC", httpReq.Headers["Date"])
	ExpectEq(computeBase64Md5(data), httpReq.Headers["Content-MD5"])
	ExpectThat(httpReq.Body, DeepEquals(data))
}

func (t *StoreObjectTest) SignerReturnsError() {
	key := "a"
	data := []byte{}

	// Signer
	ExpectCall(t.signer, "Sign")(Any()).
		WillOnce(oglemock.Return(errors.New("taco")))

	// Call
	err := t.bucket.StoreObject(key, data)

	ExpectThat(err, Error(HasSubstr("Sign")))
	ExpectThat(err, Error(HasSubstr("taco")))
}

func (t *StoreObjectTest) CallsConn() {
	key := "a"
	data := []byte{}

	// Signer
	ExpectCall(t.signer, "Sign")(Any()).
		WillOnce(oglemock.Invoke(func(r *http.Request) error {
		r.Verb = "burrito"
		return nil
	}))

	// Conn
	var httpReq *http.Request
	ExpectCall(t.httpConn, "SendRequest")(Any()).
		WillOnce(oglemock.Invoke(func(r *http.Request) (*http.Response, error) {
		httpReq = r
		return nil, errors.New("")
	}))

	// Call
	t.bucket.StoreObject(key, data)

	AssertNe(nil, httpReq)
	ExpectEq("burrito", httpReq.Verb)
}

func (t *StoreObjectTest) ConnReturnsError() {
	key := "a"
	data := []byte{}

	// Signer
	ExpectCall(t.signer, "Sign")(Any()).
		WillOnce(oglemock.Return(nil))

	// Conn
	ExpectCall(t.httpConn, "SendRequest")(Any()).
		WillOnce(oglemock.Return(nil, errors.New("taco")))

	// Call
	err := t.bucket.StoreObject(key, data)

	ExpectThat(err, Error(HasSubstr("SendRequest")))
	ExpectThat(err, Error(HasSubstr("taco")))
}

func (t *StoreObjectTest) ServerReturnsError() {
	key := "a"
	data := []byte{}

	// Signer
	ExpectCall(t.signer, "Sign")(Any()).
		WillOnce(oglemock.Return(nil))

	// Conn
	resp := &http.Response{
		StatusCode: 500,
		Body:       []byte("taco"),
	}

	ExpectCall(t.httpConn, "SendRequest")(Any()).
		WillOnce(oglemock.Return(resp, nil))

	// Call
	err := t.bucket.StoreObject(key, data)

	ExpectThat(err, Error(HasSubstr("server")))
	ExpectThat(err, Error(HasSubstr("500")))
	ExpectThat(err, Error(HasSubstr("taco")))
}

func (t *StoreObjectTest) ServerSaysOkay() {
	key := "a"
	data := []byte{}

	// Signer
	ExpectCall(t.signer, "Sign")(Any()).
		WillOnce(oglemock.Return(nil))

	// Conn
	resp := &http.Response{
		StatusCode: 200,
		Body:       []byte("taco"),
	}

	ExpectCall(t.httpConn, "SendRequest")(Any()).
		WillOnce(oglemock.Return(resp, nil))

	// Call
	err := t.bucket.StoreObject(key, data)

	ExpectEq(nil, err)
}

////////////////////////////////////////////////////////////////////////
// ListKeys
////////////////////////////////////////////////////////////////////////

type ListKeysTest struct {
	bucketTest
}

func init() { RegisterTestSuite(&ListKeysTest{}) }

func (t *ListKeysTest) CallsSignerWithEmptyMin() {
	min := ""

	// Clock
	t.clock.now = time.Date(1985, time.March, 18, 15, 33, 17, 123, time.UTC)

	// Signer
	var httpReq *http.Request
	ExpectCall(t.signer, "Sign")(Any()).
		WillOnce(oglemock.Invoke(func(r *http.Request) error {
		httpReq = r
		return errors.New("")
	}))

	// Call
	t.bucket.ListKeys(min)

	AssertNe(nil, httpReq)
	ExpectEq("GET", httpReq.Verb)
	ExpectEq("/some.bucket", httpReq.Path)
	ExpectEq("Mon, 18 Mar 1985 15:33:17 UTC", httpReq.Headers["Date"])
}

func (t *ListKeysTest) CallsSignerWithNonEmptyMin() {
	ExpectFalse(true, "TODO")
}

func (t *ListKeysTest) SignerReturnsError() {
	ExpectFalse(true, "TODO")
}

func (t *ListKeysTest) CallsConn() {
	ExpectFalse(true, "TODO")
}

func (t *ListKeysTest) ConnReturnsError() {
	ExpectFalse(true, "TODO")
}

func (t *ListKeysTest) ServerReturnsError() {
	ExpectFalse(true, "TODO")
}

func (t *ListKeysTest) ResponseBodyIsJunk() {
	ExpectFalse(true, "TODO")
}

func (t *ListKeysTest) ResponseContainsNoKeys() {
	ExpectFalse(true, "TODO")
}

func (t *ListKeysTest) ResponseContainsSomeKeys() {
	ExpectFalse(true, "TODO")
}
<|endoftext|>


<commit_before>// Package completer helps implement autocompletion.
package completer

import (
	"fmt"
	"strings"
)

// A Completer is a set of strings that can be addressed by their unique
// prefixes.
type Completer struct {
	aliases   map[string]string
	originals map[string]struct{}
}

// NewCompleter returns an empty Completer.
func NewCompleter() Completer {
	return Completer{
		aliases:   make(map[string]string),
		originals: make(map[string]struct{}),
	}
}

// Add adds s to the set of possible completions.
func (c Completer) Add(s string) error {
	if _, ok := c.aliases[s]; ok {
		if _, ok := c.originals[s]; ok {
			return fmt.Errorf("unable to add duplicate key %q", s)
		}
	}
	for i := 0; i < len(s); i++ {
		prefix := s[:i+1]
		if _, ok := c.originals[prefix]; ok {
			continue
		}
		if _, ok := c.aliases[prefix]; ok {
			delete(c.aliases, prefix)
		} else {
			c.aliases[prefix] = s
		}
	}
	c.originals[s] = struct{}{}
	return nil
}

// Lookup returns the unique completion of s, or the empty string and false if
// there is no unique completion.
func (c Completer) Lookup(s string) (string, bool) {
	got, ok := c.aliases[s]
	return got, ok
}

// Complete returns all possible completions of s.
func (c Completer) Complete(s string) []string {
	out := []string{}
	for v := range c.originals {
		if strings.HasPrefix(v, s) {
			out = append(out, v)
		}
	}
	return out
}
<commit_msg>Add FIXME on Complete() complexity<commit_after>// Package completer helps implement autocompletion.
package completer

import (
	"fmt"
	"strings"
)

// A Completer is a set of strings that can be addressed by their unique
// prefixes.
type Completer struct {
	aliases   map[string]string
	originals map[string]struct{}
}

// NewCompleter returns an empty Completer.
func NewCompleter() Completer {
	return Completer{
		aliases:   make(map[string]string),
		originals: make(map[string]struct{}),
	}
}

// Add adds s to the set of possible completions.
func (c Completer) Add(s string) error {
	if _, ok := c.aliases[s]; ok {
		if _, ok := c.originals[s]; ok {
			return fmt.Errorf("unable to add duplicate key %q", s)
		}
	}
	for i := 0; i < len(s); i++ {
		prefix := s[:i+1]
		if _, ok := c.originals[prefix]; ok {
			continue
		}
		if _, ok := c.aliases[prefix]; ok {
			delete(c.aliases, prefix)
		} else {
			c.aliases[prefix] = s
		}
	}
	c.originals[s] = struct{}{}
	return nil
}

// Lookup returns the unique completion of s, or the empty string and false if
// there is no unique completion.
func (c Completer) Lookup(s string) (string, bool) {
	got, ok := c.aliases[s]
	return got, ok
}

// Complete returns all possible completions of s.
func (c Completer) Complete(s string) []string {
	// This is O(N*M) where N is the number of originals and M is their length.
	// FIXME Find a more efficient implementation.
	out := []string{}
	for v := range c.originals {
		if strings.HasPrefix(v, s) {
			out = append(out, v)
		}
	}
	return out
}
<|endoftext|>


<commit_before>package boardgame

import (
	"crypto/sha1"
	"fmt"
	"strconv"
)

//A Component represents a movable resource in the game. Cards, dice, meeples,
//resource tokens, etc are all components. Values is a struct that stores the
//specific values for the component.
type Component struct {
	Values SubState
	//The deck we're a part of.
	Deck *Deck
	//The index we are in the deck we're in.
	DeckIndex int
}

//Id returns a semi-stable ID for this component within this game and
//currentState. Within this game, it will only change when the shuffleCount
//for this component changes. Across games the Id for the "same" component
//will be different, in a way that cannot be guessed without access to
//game.SecretSalt. See the package doc for more on semi-stable Ids for
//components, what they can be used for, and when they do (and don't) change.
func (c *Component) Id(s State) string {

	var input string

	//Shadow components shouldn't get an Id
	if c == c.Deck.GenericComponent() {
		return ""
	}

	//In some limited cases state will be nil, but in that case just make a
	//(worse) hash.
	if s != nil {
		game := s.(*state).game
		input = game.Id() + game.SecretSalt()
	}

	input += c.Deck.Name() + strconv.Itoa(c.DeckIndex)

	hash := sha1.Sum([]byte(input))

	return fmt.Sprintf("%x", hash)
}

func (c *Component) DynamicValues(state State) SubState {

	//TODO: test this

	dynamic := state.DynamicComponentValues()

	values := dynamic[c.Deck.Name()]

	if values == nil {
		return nil
	}

	if len(values) <= c.DeckIndex {
		return nil
	}

	if c.DeckIndex < 0 {
		return c.Deck.Chest().Manager().Delegate().EmptyDynamicComponentValues(c.Deck)
	}

	return values[c.DeckIndex]
}
<commit_msg>Component.Id() returns "" if the passed state is nil. A pseudo-revert of 82578. Part of #350.<commit_after>package boardgame

import (
	"crypto/sha1"
	"fmt"
	"strconv"
)

//A Component represents a movable resource in the game. Cards, dice, meeples,
//resource tokens, etc are all components. Values is a struct that stores the
//specific values for the component.
type Component struct {
	Values SubState
	//The deck we're a part of.
	Deck *Deck
	//The index we are in the deck we're in.
	DeckIndex int
}

//Id returns a semi-stable ID for this component within this game and
//currentState. Within this game, it will only change when the shuffleCount
//for this component changes. Across games the Id for the "same" component
//will be different, in a way that cannot be guessed without access to
//game.SecretSalt. See the package doc for more on semi-stable Ids for
//components, what they can be used for, and when they do (and don't) change.
func (c *Component) Id(s State) string {

	//Shadow components shouldn't get an Id
	if c == c.Deck.GenericComponent() {
		return ""
	}

	//S should  never be nil in normal circumstances, but if it is, return an
	//obviously-special Id so it doesn't appear to be the actual Id for this
	//component.
	if s == nil {
		return ""
	}

	game := s.(*state).game
	input := game.Id() + game.SecretSalt()

	input += c.Deck.Name() + strconv.Itoa(c.DeckIndex)

	hash := sha1.Sum([]byte(input))

	return fmt.Sprintf("%x", hash)
}

func (c *Component) DynamicValues(state State) SubState {

	//TODO: test this

	dynamic := state.DynamicComponentValues()

	values := dynamic[c.Deck.Name()]

	if values == nil {
		return nil
	}

	if len(values) <= c.DeckIndex {
		return nil
	}

	if c.DeckIndex < 0 {
		return c.Deck.Chest().Manager().Delegate().EmptyDynamicComponentValues(c.Deck)
	}

	return values[c.DeckIndex]
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"net/http"
	"regexp"
	"strconv"
	"testing"
	"time"
)

// Test that useful common cache-related parameters are sent to the
// client by this CDN provider.

// Should propagate an Age header from origin and then increment it for the
// time it's in cache.
func TestRespHeaderAge(t *testing.T) {
	ResetBackends(backendsByPriority)

	const originAgeInSeconds = 100
	const secondsToWaitBetweenRequests = 5
	const expectedAgeInSeconds = originAgeInSeconds + secondsToWaitBetweenRequests
	requestReceivedCount := 0

	originServer.SwitchHandler(func(w http.ResponseWriter, r *http.Request) {
		if requestReceivedCount == 0 {
			w.Header().Set("Cache-Control", "max-age=1800, public")
			w.Header().Set("Age", fmt.Sprintf("%d", originAgeInSeconds))
			w.Write([]byte("cacheable request"))
		} else {
			t.Error("Unexpected subsequent request received at Origin")
		}
		requestReceivedCount++
	})

	req := NewUniqueEdgeGET(t)
	resp := RoundTripCheckError(t, req)
	defer resp.Body.Close()

	if resp.StatusCode != 200 {
		t.Fatalf("Edge returned an unexpected status: %q", resp.Status)
	}

	// wait a little bit. Edge should update the Age header, we know Origin will not
	time.Sleep(time.Duration(secondsToWaitBetweenRequests) * time.Second)
	resp = RoundTripCheckError(t, req)
	defer resp.Body.Close()

	if resp.StatusCode != 200 {
		t.Fatalf("Edge returned an unexpected status: %q", resp.Status)
	}

	edgeAgeHeader := resp.Header.Get("Age")
	if edgeAgeHeader == "" {
		t.Fatal("Age Header is not set")
	}

	edgeAgeInSeconds, convErr := strconv.Atoi(edgeAgeHeader)
	if convErr != nil {
		t.Fatal(convErr)
	}

	if edgeAgeInSeconds != expectedAgeInSeconds {
		t.Errorf(
			"Age header from Edge is not as expected. Got %q, expected '%d'",
			edgeAgeHeader,
			expectedAgeInSeconds,
		)
	}
}

// Should set an X-Cache header containing HIT/MISS from 'origin, itself'
func TestRespHeaderXCacheAppend(t *testing.T) {
	ResetBackends(backendsByPriority)

	const originXCache = "HIT"

	var (
		xCache         string
		expectedXCache string
	)

	originServer.SwitchHandler(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("X-Cache", originXCache)
	})

	// Get first request, will come from origin, cannot be cached - hence cache MISS
	req := NewUniqueEdgeGET(t)
	resp := RoundTripCheckError(t, req)
	defer resp.Body.Close()

	xCache = resp.Header.Get("X-Cache")
	expectedXCache = fmt.Sprintf("%s, MISS", originXCache)
	if xCache != expectedXCache {
		t.Errorf(
			"X-Cache on initial hit is wrong: expected %q, got %q",
			expectedXCache,
			xCache,
		)
	}

}

// Should set an X-Cache header containing only MISS if origin does not set an X-Cache Header'
func TestRespHeaderXCacheCreate(t *testing.T) {
	ResetBackends(backendsByPriority)

	const expectedXCache = "MISS"

	var (
		xCache string
	)

	// Get first request, will come from origin, cannot be cached - hence cache MISS
	req := NewUniqueEdgeGET(t)
	resp := RoundTripCheckError(t, req)
	defer resp.Body.Close()

	xCache = resp.Header.Get("X-Cache")
	if xCache != expectedXCache {
		t.Errorf(
			"X-Cache on initial hit is wrong: expected %q, got %q",
			expectedXCache,
			xCache,
		)
	}

}

// Should set an X-Served-By header giving information on the (Fastly) node and location served from.
func TestRespHeaderXServedBy(t *testing.T) {
	ResetBackends(backendsByPriority)

	expectedFastlyXServedByRegexp := regexp.MustCompile("^cache-[a-z0-9]+-[A-Z]{3}$")

	req := NewUniqueEdgeGET(t)
	resp := RoundTripCheckError(t, req)
	defer resp.Body.Close()

	actualHeader := resp.Header.Get("X-Served-By")
	if actualHeader == "" {
		t.Error("X-Served-By header has not been set by Edge")
	}

	if expectedFastlyXServedByRegexp.FindString(actualHeader) != actualHeader {
		t.Errorf("X-Served-By is not as expected: got %q", actualHeader)
	}

}

// Should set an X-Cache-Hits header containing hit count for this object,
// from the Edge AND the Origin, assuming Origin sets one.
// This is in the format "{origin-hit-count}, {edge-hit-count}"
func TestRespHeaderXCacheHitsAppend(t *testing.T) {
	ResetBackends(backendsByPriority)

	const originXCacheHits = "53"

	var (
		xCacheHits         string
		expectedXCacheHits string
	)

	uuid := NewUUID()

	originServer.SwitchHandler(func(w http.ResponseWriter, r *http.Request) {
		if r.Method == "GET" && r.URL.Path == fmt.Sprintf("/%s", uuid) {
			w.Header().Set("X-Cache-Hits", originXCacheHits)
		}
	})

	sourceUrl := fmt.Sprintf("https://%s/%s", *edgeHost, uuid)

	// Get first request, will come from origin. Edge Hit Count 0
	req, _ := http.NewRequest("GET", sourceUrl, nil)
	resp := RoundTripCheckError(t, req)
	defer resp.Body.Close()

	xCacheHits = resp.Header.Get("X-Cache-Hits")
	expectedXCacheHits = fmt.Sprintf("%s, 0", originXCacheHits)
	if xCacheHits != expectedXCacheHits {
		t.Errorf(
			"X-Cache-Hits on initial hit is wrong: expected %q, got %q",
			expectedXCacheHits,
			xCacheHits,
		)
	}

	// Get request again. Should come from Edge now, hit count 1
	resp = RoundTripCheckError(t, req)
	defer resp.Body.Close()

	xCacheHits = resp.Header.Get("X-Cache-Hits")
	expectedXCacheHits = fmt.Sprintf("%s, 1", originXCacheHits)
	if xCacheHits != expectedXCacheHits {
		t.Errorf(
			"X-Cache-Hits on second hit is wrong: expected %q, got %q",
			expectedXCacheHits,
			xCacheHits,
		)
	}
}
<commit_msg>Repurpose X-Served-By test to be generic<commit_after>package main

import (
	"fmt"
	"net/http"
	"regexp"
	"strconv"
	"testing"
	"time"
)

// Test that useful common cache-related parameters are sent to the
// client by this CDN provider.

// Should propagate an Age header from origin and then increment it for the
// time it's in cache.
func TestRespHeaderAge(t *testing.T) {
	ResetBackends(backendsByPriority)

	const originAgeInSeconds = 100
	const secondsToWaitBetweenRequests = 5
	const expectedAgeInSeconds = originAgeInSeconds + secondsToWaitBetweenRequests
	requestReceivedCount := 0

	originServer.SwitchHandler(func(w http.ResponseWriter, r *http.Request) {
		if requestReceivedCount == 0 {
			w.Header().Set("Cache-Control", "max-age=1800, public")
			w.Header().Set("Age", fmt.Sprintf("%d", originAgeInSeconds))
			w.Write([]byte("cacheable request"))
		} else {
			t.Error("Unexpected subsequent request received at Origin")
		}
		requestReceivedCount++
	})

	req := NewUniqueEdgeGET(t)
	resp := RoundTripCheckError(t, req)
	defer resp.Body.Close()

	if resp.StatusCode != 200 {
		t.Fatalf("Edge returned an unexpected status: %q", resp.Status)
	}

	// wait a little bit. Edge should update the Age header, we know Origin will not
	time.Sleep(time.Duration(secondsToWaitBetweenRequests) * time.Second)
	resp = RoundTripCheckError(t, req)
	defer resp.Body.Close()

	if resp.StatusCode != 200 {
		t.Fatalf("Edge returned an unexpected status: %q", resp.Status)
	}

	edgeAgeHeader := resp.Header.Get("Age")
	if edgeAgeHeader == "" {
		t.Fatal("Age Header is not set")
	}

	edgeAgeInSeconds, convErr := strconv.Atoi(edgeAgeHeader)
	if convErr != nil {
		t.Fatal(convErr)
	}

	if edgeAgeInSeconds != expectedAgeInSeconds {
		t.Errorf(
			"Age header from Edge is not as expected. Got %q, expected '%d'",
			edgeAgeHeader,
			expectedAgeInSeconds,
		)
	}
}

// Should set an X-Cache header containing HIT/MISS from 'origin, itself'
func TestRespHeaderXCacheAppend(t *testing.T) {
	ResetBackends(backendsByPriority)

	const originXCache = "HIT"

	var (
		xCache         string
		expectedXCache string
	)

	originServer.SwitchHandler(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("X-Cache", originXCache)
	})

	// Get first request, will come from origin, cannot be cached - hence cache MISS
	req := NewUniqueEdgeGET(t)
	resp := RoundTripCheckError(t, req)
	defer resp.Body.Close()

	xCache = resp.Header.Get("X-Cache")
	expectedXCache = fmt.Sprintf("%s, MISS", originXCache)
	if xCache != expectedXCache {
		t.Errorf(
			"X-Cache on initial hit is wrong: expected %q, got %q",
			expectedXCache,
			xCache,
		)
	}

}

// Should set an X-Cache header containing only MISS if origin does not set an X-Cache Header'
func TestRespHeaderXCacheCreate(t *testing.T) {
	ResetBackends(backendsByPriority)

	const expectedXCache = "MISS"

	var (
		xCache string
	)

	// Get first request, will come from origin, cannot be cached - hence cache MISS
	req := NewUniqueEdgeGET(t)
	resp := RoundTripCheckError(t, req)
	defer resp.Body.Close()

	xCache = resp.Header.Get("X-Cache")
	if xCache != expectedXCache {
		t.Errorf(
			"X-Cache on initial hit is wrong: expected %q, got %q",
			expectedXCache,
			xCache,
		)
	}

}

// Should set an 'Served-By' header giving information on the edge node and location served from.
func TestRespHeaderServedBy(t *testing.T) {
	ResetBackends(backendsByPriority)

	var expectedServedByRegexp *regexp.Regexp
	var headerName string

	switch {
	case testForCloudflare:
		headerName = "CF-RAY"
		expectedServedByRegexp = regexp.MustCompile("^[a-z0-9]{16}-[A-Z]{3}$")
	case testForFastly:
		headerName = "X-Served-By"
		expectedServedByRegexp = regexp.MustCompile("^cache-[a-z0-9]+-[A-Z]{3}$")
	default:
		t.Skip(skipVendorMsg)
	}

	req := NewUniqueEdgeGET(t)
	resp := RoundTripCheckError(t, req)
	defer resp.Body.Close()

	actualHeader := resp.Header.Get(headerName)

	if actualHeader == "" {
		t.Error(headerName + " header has not been set by Edge")
	}

	if expectedServedByRegexp.FindString(actualHeader) != actualHeader {
		t.Errorf("%s is not as expected: got %q", headerName, actualHeader)
	}

}

// Should set an X-Cache-Hits header containing hit count for this object,
// from the Edge AND the Origin, assuming Origin sets one.
// This is in the format "{origin-hit-count}, {edge-hit-count}"
func TestRespHeaderXCacheHitsAppend(t *testing.T) {
	ResetBackends(backendsByPriority)

	const originXCacheHits = "53"

	var (
		xCacheHits         string
		expectedXCacheHits string
	)

	uuid := NewUUID()

	originServer.SwitchHandler(func(w http.ResponseWriter, r *http.Request) {
		if r.Method == "GET" && r.URL.Path == fmt.Sprintf("/%s", uuid) {
			w.Header().Set("X-Cache-Hits", originXCacheHits)
		}
	})

	sourceUrl := fmt.Sprintf("https://%s/%s", *edgeHost, uuid)

	// Get first request, will come from origin. Edge Hit Count 0
	req, _ := http.NewRequest("GET", sourceUrl, nil)
	resp := RoundTripCheckError(t, req)
	defer resp.Body.Close()

	xCacheHits = resp.Header.Get("X-Cache-Hits")
	expectedXCacheHits = fmt.Sprintf("%s, 0", originXCacheHits)
	if xCacheHits != expectedXCacheHits {
		t.Errorf(
			"X-Cache-Hits on initial hit is wrong: expected %q, got %q",
			expectedXCacheHits,
			xCacheHits,
		)
	}

	// Get request again. Should come from Edge now, hit count 1
	resp = RoundTripCheckError(t, req)
	defer resp.Body.Close()

	xCacheHits = resp.Header.Get("X-Cache-Hits")
	expectedXCacheHits = fmt.Sprintf("%s, 1", originXCacheHits)
	if xCacheHits != expectedXCacheHits {
		t.Errorf(
			"X-Cache-Hits on second hit is wrong: expected %q, got %q",
			expectedXCacheHits,
			xCacheHits,
		)
	}
}
<|endoftext|>


<commit_before>package crypto

import (
	"crypto/cipher"
	"crypto/rand"
	"io"

	"v2ray.com/core/common"
	"v2ray.com/core/common/buf"
	"v2ray.com/core/common/protocol"
)

type BytesGenerator func() []byte

func GenerateEmptyBytes() BytesGenerator {
	var b [1]byte
	return func() []byte {
		return b[:0]
	}
}

func GenerateStaticBytes(content []byte) BytesGenerator {
	return func() []byte {
		return content
	}
}

func GenerateIncreasingNonce(nonce []byte) BytesGenerator {
	c := append([]byte(nil), nonce...)
	return func() []byte {
		for i := range c {
			c[i]++
			if c[i] != 0 {
				break
			}
		}
		return c
	}
}

func GenerateInitialAEADNonce() BytesGenerator {
	return GenerateIncreasingNonce([]byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF})
}

type Authenticator interface {
	NonceSize() int
	Overhead() int
	Open(dst, cipherText []byte) ([]byte, error)
	Seal(dst, plainText []byte) ([]byte, error)
}

type AEADAuthenticator struct {
	cipher.AEAD
	NonceGenerator          BytesGenerator
	AdditionalDataGenerator BytesGenerator
}

func (v *AEADAuthenticator) Open(dst, cipherText []byte) ([]byte, error) {
	iv := v.NonceGenerator()
	if len(iv) != v.AEAD.NonceSize() {
		return nil, newError("invalid AEAD nonce size: ", len(iv))
	}

	var additionalData []byte
	if v.AdditionalDataGenerator != nil {
		additionalData = v.AdditionalDataGenerator()
	}
	return v.AEAD.Open(dst, iv, cipherText, additionalData)
}

func (v *AEADAuthenticator) Seal(dst, plainText []byte) ([]byte, error) {
	iv := v.NonceGenerator()
	if len(iv) != v.AEAD.NonceSize() {
		return nil, newError("invalid AEAD nonce size: ", len(iv))
	}

	var additionalData []byte
	if v.AdditionalDataGenerator != nil {
		additionalData = v.AdditionalDataGenerator()
	}
	return v.AEAD.Seal(dst, iv, plainText, additionalData), nil
}

type AuthenticationReader struct {
	auth         Authenticator
	reader       *buf.BufferedReader
	sizeParser   ChunkSizeDecoder
	transferType protocol.TransferType
	padding      PaddingLengthGenerator
	size         int32
	paddingLen   int32
}

func NewAuthenticationReader(auth Authenticator, sizeParser ChunkSizeDecoder, reader io.Reader, transferType protocol.TransferType, paddingLen PaddingLengthGenerator) *AuthenticationReader {
	return &AuthenticationReader{
		auth:         auth,
		reader:       &buf.BufferedReader{Reader: buf.NewReader(reader)},
		sizeParser:   sizeParser,
		transferType: transferType,
		padding:      paddingLen,
		size:         -1,
		paddingLen:   -1,
	}
}

func (r *AuthenticationReader) readSize() (int32, int32, error) {
	if r.size != -1 {
		s := r.size
		r.size = -1
		return s, r.paddingLen, nil
	}
	sizeBytes := make([]byte, r.sizeParser.SizeBytes())
	if _, err := io.ReadFull(r.reader, sizeBytes); err != nil {
		return 0, 0, err
	}
	var padding int32
	if r.padding != nil {
		padding = int32(r.padding.NextPaddingLen())
	}
	size, err := r.sizeParser.Decode(sizeBytes)
	return int32(size), padding, err
}

var errSoft = newError("waiting for more data")

func (r *AuthenticationReader) readInternal(soft bool) (*buf.Buffer, error) {
	if soft && r.reader.BufferedBytes() < r.sizeParser.SizeBytes() {
		return nil, errSoft
	}

	size, padding, err := r.readSize()
	if err != nil {
		return nil, err
	}

	if size == -2 || size == int32(r.auth.Overhead())+padding {
		r.size = -2
		return nil, io.EOF
	}

	if soft && size > r.reader.BufferedBytes() {
		r.size = size
		r.paddingLen = padding
		return nil, errSoft
	}

	b := buf.NewSize(size)
	if err := b.Reset(buf.ReadFullFrom(r.reader, size)); err != nil {
		b.Release()
		return nil, err
	}

	size -= padding

	rb, err := r.auth.Open(b.BytesTo(0), b.BytesTo(size))
	if err != nil {
		b.Release()
		return nil, err
	}
	b.Resize(0, int32(len(rb)))

	return b, nil
}

func (r *AuthenticationReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
	b, err := r.readInternal(false)
	if err != nil {
		return nil, err
	}

	mb := buf.NewMultiBufferCap(32)
	mb.Append(b)

	for {
		b, err := r.readInternal(true)
		if err == errSoft || err == io.EOF {
			break
		}
		if err != nil {
			mb.Release()
			return nil, err
		}
		mb.Append(b)
	}

	return mb, nil
}

type AuthenticationWriter struct {
	auth         Authenticator
	writer       buf.Writer
	sizeParser   ChunkSizeEncoder
	transferType protocol.TransferType
	padding      PaddingLengthGenerator
}

func NewAuthenticationWriter(auth Authenticator, sizeParser ChunkSizeEncoder, writer io.Writer, transferType protocol.TransferType, padding PaddingLengthGenerator) *AuthenticationWriter {
	return &AuthenticationWriter{
		auth:         auth,
		writer:       buf.NewWriter(writer),
		sizeParser:   sizeParser,
		transferType: transferType,
		padding:      padding,
	}
}

func (w *AuthenticationWriter) seal(b *buf.Buffer) (*buf.Buffer, error) {
	encryptedSize := int(b.Len()) + w.auth.Overhead()
	paddingSize := 0
	if w.padding != nil {
		paddingSize = int(w.padding.NextPaddingLen())
	}

	eb := buf.New()
	common.Must(eb.Reset(func(bb []byte) (int, error) {
		w.sizeParser.Encode(uint16(encryptedSize+paddingSize), bb[:0])
		return int(w.sizeParser.SizeBytes()), nil
	}))
	if err := eb.AppendSupplier(func(bb []byte) (int, error) {
		_, err := w.auth.Seal(bb[:0], b.Bytes())
		return encryptedSize, err
	}); err != nil {
		eb.Release()
		return nil, err
	}
	if paddingSize > 0 {
		if err := eb.AppendSupplier(func(bb []byte) (int, error) {
			common.Must2(rand.Read(bb[:paddingSize]))
			return paddingSize, nil
		}); err != nil {
			eb.Release()
			return nil, err
		}
	}

	return eb, nil
}

func (w *AuthenticationWriter) writeStream(mb buf.MultiBuffer) error {
	defer mb.Release()

	payloadSize := buf.Size - int32(w.auth.Overhead()) - w.sizeParser.SizeBytes() - 64 /* padding buffer */
	mb2Write := buf.NewMultiBufferCap(int32(len(mb) + 10))

	for {
		b := buf.New()
		common.Must(b.Reset(func(bb []byte) (int, error) {
			return mb.Read(bb[:payloadSize])
		}))
		eb, err := w.seal(b)
		b.Release()

		if err != nil {
			mb2Write.Release()
			return err
		}
		mb2Write.Append(eb)
		if mb.IsEmpty() {
			break
		}
	}

	return w.writer.WriteMultiBuffer(mb2Write)
}

func (w *AuthenticationWriter) writePacket(mb buf.MultiBuffer) error {
	defer mb.Release()

	mb2Write := buf.NewMultiBufferCap(int32(len(mb)) + 1)

	for !mb.IsEmpty() {
		b := mb.SplitFirst()
		if b == nil {
			continue
		}
		eb, err := w.seal(b)
		b.Release()
		if err != nil {
			mb2Write.Release()
			return err
		}
		mb2Write.Append(eb)
	}

	return w.writer.WriteMultiBuffer(mb2Write)
}

func (w *AuthenticationWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
	if mb.IsEmpty() {
		b := buf.New()
		defer b.Release()

		eb, _ := w.seal(b)
		return w.writer.WriteMultiBuffer(buf.NewMultiBufferValue(eb))
	}

	if w.transferType == protocol.TransferTypeStream {
		return w.writeStream(mb)
	}

	return w.writePacket(mb)
}
<commit_msg>fix padding value<commit_after>package crypto

import (
	"crypto/cipher"
	"crypto/rand"
	"io"

	"v2ray.com/core/common"
	"v2ray.com/core/common/buf"
	"v2ray.com/core/common/protocol"
)

type BytesGenerator func() []byte

func GenerateEmptyBytes() BytesGenerator {
	var b [1]byte
	return func() []byte {
		return b[:0]
	}
}

func GenerateStaticBytes(content []byte) BytesGenerator {
	return func() []byte {
		return content
	}
}

func GenerateIncreasingNonce(nonce []byte) BytesGenerator {
	c := append([]byte(nil), nonce...)
	return func() []byte {
		for i := range c {
			c[i]++
			if c[i] != 0 {
				break
			}
		}
		return c
	}
}

func GenerateInitialAEADNonce() BytesGenerator {
	return GenerateIncreasingNonce([]byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF})
}

type Authenticator interface {
	NonceSize() int
	Overhead() int
	Open(dst, cipherText []byte) ([]byte, error)
	Seal(dst, plainText []byte) ([]byte, error)
}

type AEADAuthenticator struct {
	cipher.AEAD
	NonceGenerator          BytesGenerator
	AdditionalDataGenerator BytesGenerator
}

func (v *AEADAuthenticator) Open(dst, cipherText []byte) ([]byte, error) {
	iv := v.NonceGenerator()
	if len(iv) != v.AEAD.NonceSize() {
		return nil, newError("invalid AEAD nonce size: ", len(iv))
	}

	var additionalData []byte
	if v.AdditionalDataGenerator != nil {
		additionalData = v.AdditionalDataGenerator()
	}
	return v.AEAD.Open(dst, iv, cipherText, additionalData)
}

func (v *AEADAuthenticator) Seal(dst, plainText []byte) ([]byte, error) {
	iv := v.NonceGenerator()
	if len(iv) != v.AEAD.NonceSize() {
		return nil, newError("invalid AEAD nonce size: ", len(iv))
	}

	var additionalData []byte
	if v.AdditionalDataGenerator != nil {
		additionalData = v.AdditionalDataGenerator()
	}
	return v.AEAD.Seal(dst, iv, plainText, additionalData), nil
}

type AuthenticationReader struct {
	auth         Authenticator
	reader       *buf.BufferedReader
	sizeParser   ChunkSizeDecoder
	transferType protocol.TransferType
	padding      PaddingLengthGenerator
	size         int32
	paddingLen   int32
}

func NewAuthenticationReader(auth Authenticator, sizeParser ChunkSizeDecoder, reader io.Reader, transferType protocol.TransferType, paddingLen PaddingLengthGenerator) *AuthenticationReader {
	return &AuthenticationReader{
		auth:         auth,
		reader:       &buf.BufferedReader{Reader: buf.NewReader(reader)},
		sizeParser:   sizeParser,
		transferType: transferType,
		padding:      paddingLen,
		size:         -1,
	}
}

func (r *AuthenticationReader) readSize() (int32, int32, error) {
	if r.size != -1 {
		s := r.size
		r.size = -1
		return s, r.paddingLen, nil
	}
	sizeBytes := make([]byte, r.sizeParser.SizeBytes())
	if _, err := io.ReadFull(r.reader, sizeBytes); err != nil {
		return 0, 0, err
	}
	var padding int32
	if r.padding != nil {
		padding = int32(r.padding.NextPaddingLen())
	}
	size, err := r.sizeParser.Decode(sizeBytes)
	return int32(size), padding, err
}

var errSoft = newError("waiting for more data")

func (r *AuthenticationReader) readInternal(soft bool) (*buf.Buffer, error) {
	if soft && r.reader.BufferedBytes() < r.sizeParser.SizeBytes() {
		return nil, errSoft
	}

	size, padding, err := r.readSize()
	if err != nil {
		return nil, err
	}

	if size == -2 || size == int32(r.auth.Overhead())+padding {
		r.size = -2
		return nil, io.EOF
	}

	if soft && size > r.reader.BufferedBytes() {
		r.size = size
		r.paddingLen = padding
		return nil, errSoft
	}

	b := buf.NewSize(size)
	if err := b.Reset(buf.ReadFullFrom(r.reader, size)); err != nil {
		b.Release()
		return nil, err
	}

	size -= padding

	rb, err := r.auth.Open(b.BytesTo(0), b.BytesTo(size))
	if err != nil {
		b.Release()
		return nil, err
	}
	b.Resize(0, int32(len(rb)))

	return b, nil
}

func (r *AuthenticationReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
	b, err := r.readInternal(false)
	if err != nil {
		return nil, err
	}

	mb := buf.NewMultiBufferCap(32)
	mb.Append(b)

	for {
		b, err := r.readInternal(true)
		if err == errSoft || err == io.EOF {
			break
		}
		if err != nil {
			mb.Release()
			return nil, err
		}
		mb.Append(b)
	}

	return mb, nil
}

type AuthenticationWriter struct {
	auth         Authenticator
	writer       buf.Writer
	sizeParser   ChunkSizeEncoder
	transferType protocol.TransferType
	padding      PaddingLengthGenerator
}

func NewAuthenticationWriter(auth Authenticator, sizeParser ChunkSizeEncoder, writer io.Writer, transferType protocol.TransferType, padding PaddingLengthGenerator) *AuthenticationWriter {
	return &AuthenticationWriter{
		auth:         auth,
		writer:       buf.NewWriter(writer),
		sizeParser:   sizeParser,
		transferType: transferType,
		padding:      padding,
	}
}

func (w *AuthenticationWriter) seal(b *buf.Buffer) (*buf.Buffer, error) {
	encryptedSize := int(b.Len()) + w.auth.Overhead()
	paddingSize := 0
	if w.padding != nil {
		paddingSize = int(w.padding.NextPaddingLen())
	}

	eb := buf.New()
	common.Must(eb.Reset(func(bb []byte) (int, error) {
		w.sizeParser.Encode(uint16(encryptedSize+paddingSize), bb[:0])
		return int(w.sizeParser.SizeBytes()), nil
	}))
	if err := eb.AppendSupplier(func(bb []byte) (int, error) {
		_, err := w.auth.Seal(bb[:0], b.Bytes())
		return encryptedSize, err
	}); err != nil {
		eb.Release()
		return nil, err
	}
	if paddingSize > 0 {
		if err := eb.AppendSupplier(func(bb []byte) (int, error) {
			common.Must2(rand.Read(bb[:paddingSize]))
			return paddingSize, nil
		}); err != nil {
			eb.Release()
			return nil, err
		}
	}

	return eb, nil
}

func (w *AuthenticationWriter) writeStream(mb buf.MultiBuffer) error {
	defer mb.Release()

	payloadSize := buf.Size - int32(w.auth.Overhead()) - w.sizeParser.SizeBytes() - 64 /* padding buffer */
	mb2Write := buf.NewMultiBufferCap(int32(len(mb) + 10))

	for {
		b := buf.New()
		common.Must(b.Reset(func(bb []byte) (int, error) {
			return mb.Read(bb[:payloadSize])
		}))
		eb, err := w.seal(b)
		b.Release()

		if err != nil {
			mb2Write.Release()
			return err
		}
		mb2Write.Append(eb)
		if mb.IsEmpty() {
			break
		}
	}

	return w.writer.WriteMultiBuffer(mb2Write)
}

func (w *AuthenticationWriter) writePacket(mb buf.MultiBuffer) error {
	defer mb.Release()

	mb2Write := buf.NewMultiBufferCap(int32(len(mb)) + 1)

	for !mb.IsEmpty() {
		b := mb.SplitFirst()
		if b == nil {
			continue
		}
		eb, err := w.seal(b)
		b.Release()
		if err != nil {
			mb2Write.Release()
			return err
		}
		mb2Write.Append(eb)
	}

	return w.writer.WriteMultiBuffer(mb2Write)
}

func (w *AuthenticationWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
	if mb.IsEmpty() {
		b := buf.New()
		defer b.Release()

		eb, _ := w.seal(b)
		return w.writer.WriteMultiBuffer(buf.NewMultiBufferValue(eb))
	}

	if w.transferType == protocol.TransferTypeStream {
		return w.writeStream(mb)
	}

	return w.writePacket(mb)
}
<|endoftext|>


<commit_before>// The foxpro package is a database/sql driver for ADO connections to FoxPro
// databases.
package foxpro

import (
	"code.google.com/p/com-and-go"
	"database/sql"
	"database/sql/driver"
	"errors"
	"fmt"
	"io"
	"strings"
	"time"
)

func init() {
	sql.Register("foxpro", foxDriver{})
}

type foxDriver struct{}

func (d foxDriver) Open(name string) (driver.Conn, error) {
	err := com.CoInitializeEx(0, 0)
	if err != nil {
		return nil, err
	}

	db, err := com.NewIDispatch("ADODB.Connection")
	if err != nil {
		return nil, err
	}

	c := &conn{
		db: db,
	}
	dsn := fmt.Sprintf("Provider=vfpoledb;Data Source=%s;", name)
	_, err = db.Call("Open", dsn)
	if err != nil {
		return nil, err
	}

	return c, nil
}

type conn struct {
	db *com.IDispatch
}

func (c *conn) Prepare(query string) (driver.Stmt, error) {
	return &stmt{c, query}, nil
}

func (c *conn) Close() error {
	_, err := c.db.Call("Close")
	return err
}

func (c *conn) Begin() (driver.Tx, error) {
	return nil, errors.New("foxpro: transactions aren't supported yet.")
}

type stmt struct {
	c     *conn
	query string
}

func (s *stmt) Close() error {
	return nil
}

func (s *stmt) NumInput() int {
	return -1
}

func (s *stmt) Exec(args []driver.Value) (driver.Result, error) {
	_, result, err := s.q(args)
	return result, err
}

func (s *stmt) Query(args []driver.Value) (driver.Rows, error) {
	rows, _, err := s.q(args)
	return rows, err
}

func (s *stmt) q(args []driver.Value) (driver.Rows, driver.Result, error) {
	cmd, err := com.NewIDispatch("ADODB.Command")
	if err != nil {
		return nil, nil, err
	}
	defer cmd.Release()
	err = cmd.Put("ActiveConnection", s.c.db)
	if err != nil {
		return nil, nil, err
	}

	err = cmd.Put("CommandText", s.query)
	if err != nil {
		return nil, nil, err
	}
	err = cmd.Put("CommandType", 1)
	if err != nil {
		return nil, nil, err
	}

	x, err := cmd.Get("Parameters")
	if err != nil {
		return nil, nil, err
	}
	params := x.(*com.IDispatch)
	defer params.Release()

	for _, a := range args {
		var p interface{} // the parameter object
		switch v := a.(type) {
		case int64:
			v32 := int32(v)
			if int64(v32) != v {
				return nil, nil, fmt.Errorf("integer too large to pass to FoxPro: %d", v)
			}
			p, err = cmd.Call("CreateParameter", "", 3 /* adInteger */, 1, 4, v32)
		case float64:
			p, err = cmd.Call("CreateParameter", "", 5 /* adDouble */, 1, 8, v)
		case bool:
			p, err = cmd.Call("CreateParameter", "", 11 /* adBoolean */, 1, 1, v)
		case []byte:
			p, err = cmd.Call("CreateParameter", "", 8 /* adBSTR */, 1, len(v), string(v))
		case string:
			p, err = cmd.Call("CreateParameter", "", 8 /* adBSTR */, 1, len(v), v)
		case time.Time:
			p, err = cmd.Call("CreateParameter", "", 7 /* adDate */, 1, 8, v)
		default:
			err = fmt.Errorf("foxpro: parameters of type %T are not supported", a)
		}
		if err != nil {
			return nil, nil, err
		}
		param := p.(*com.IDispatch)
		defer param.Release()
		_, err = params.Call("Append", param)
		if err != nil {
			return nil, nil, err
		}
	}

	var nRecords int32
	x, err = cmd.Call("Execute", &nRecords)
	if err != nil {
		return nil, nil, err
	}
	recordset := x.(*com.IDispatch)
	return &rows{recordset}, driver.RowsAffected(nRecords), nil
}

type rows struct {
	rs *com.IDispatch
}

func (r *rows) Columns() []string {
	x, err := r.rs.Get("Fields")
	if err != nil {
		panic(err)
	}
	fields := x.(*com.IDispatch)
	defer fields.Release()

	x, err = fields.Get("Count")
	if err != nil {
		panic(err)
	}
	n := x.(int32)

	cols := make([]string, n)
	for i := int32(0); i < n; i++ {
		x, err = fields.Call("Item", i)
		if err != nil {
			panic(err)
		}
		item := x.(*com.IDispatch)
		defer item.Release()

		x, err = item.Get("Name")
		if err != nil {
			panic(err)
		}
		cols[i] = x.(string)
	}
	return cols
}

func (r *rows) Close() error {
	r.rs.Release()
	r.rs = nil
	return nil
}

func (r *rows) Next(dest []driver.Value) error {
	x, err := r.rs.Get("EOF")
	if err != nil {
		return err
	}
	if x == true {
		return io.EOF
	}

	x, err = r.rs.Get("Fields")
	if err != nil {
		return err
	}
	fields := x.(*com.IDispatch)
	defer fields.Release()

	for i := range dest {
		x, err = fields.Call("Item", int32(i))
		if err != nil {
			return err
		}
		item := x.(*com.IDispatch)
		defer item.Release()

		x, err = item.Get("Value")
		if err != nil {
			return err
		}
		switch v := x.(type) {
		case string:
			dest[i] = strings.TrimRight(v, " ")
		case int32:
			dest[i] = int64(v)
		case bool:
			dest[i] = v
		case com.Decimal:
			dest[i] = v.String()
		case time.Time:
			dest[i] = v
		case float64:
			dest[i] = v
		case com.Variant:
			return fmt.Errorf("foxpro: result variant with VT=%d not supported yet", v.VT)
		default:
			return fmt.Errorf("foxpro: result type %T not supported yet", v)
		}
	}

	_, err = r.rs.Call("MoveNext")
	if err != nil {
		return err
	}
	return nil
}
<commit_msg>Support null column values in Foxpro driver.<commit_after>// The foxpro package is a database/sql driver for ADO connections to FoxPro
// databases.
package foxpro

import (
	"code.google.com/p/com-and-go"
	"database/sql"
	"database/sql/driver"
	"errors"
	"fmt"
	"io"
	"strings"
	"time"
)

func init() {
	sql.Register("foxpro", foxDriver{})
}

type foxDriver struct{}

func (d foxDriver) Open(name string) (driver.Conn, error) {
	err := com.CoInitializeEx(0, 0)
	if err != nil {
		return nil, err
	}

	db, err := com.NewIDispatch("ADODB.Connection")
	if err != nil {
		return nil, err
	}

	c := &conn{
		db: db,
	}
	dsn := fmt.Sprintf("Provider=vfpoledb;Data Source=%s;", name)
	_, err = db.Call("Open", dsn)
	if err != nil {
		return nil, err
	}

	return c, nil
}

type conn struct {
	db *com.IDispatch
}

func (c *conn) Prepare(query string) (driver.Stmt, error) {
	return &stmt{c, query}, nil
}

func (c *conn) Close() error {
	_, err := c.db.Call("Close")
	return err
}

func (c *conn) Begin() (driver.Tx, error) {
	return nil, errors.New("foxpro: transactions aren't supported yet.")
}

type stmt struct {
	c     *conn
	query string
}

func (s *stmt) Close() error {
	return nil
}

func (s *stmt) NumInput() int {
	return -1
}

func (s *stmt) Exec(args []driver.Value) (driver.Result, error) {
	_, result, err := s.q(args)
	return result, err
}

func (s *stmt) Query(args []driver.Value) (driver.Rows, error) {
	rows, _, err := s.q(args)
	return rows, err
}

func (s *stmt) q(args []driver.Value) (driver.Rows, driver.Result, error) {
	cmd, err := com.NewIDispatch("ADODB.Command")
	if err != nil {
		return nil, nil, err
	}
	defer cmd.Release()
	err = cmd.Put("ActiveConnection", s.c.db)
	if err != nil {
		return nil, nil, err
	}

	err = cmd.Put("CommandText", s.query)
	if err != nil {
		return nil, nil, err
	}
	err = cmd.Put("CommandType", 1)
	if err != nil {
		return nil, nil, err
	}

	x, err := cmd.Get("Parameters")
	if err != nil {
		return nil, nil, err
	}
	params := x.(*com.IDispatch)
	defer params.Release()

	for _, a := range args {
		var p interface{} // the parameter object
		switch v := a.(type) {
		case int64:
			v32 := int32(v)
			if int64(v32) != v {
				return nil, nil, fmt.Errorf("integer too large to pass to FoxPro: %d", v)
			}
			p, err = cmd.Call("CreateParameter", "", 3 /* adInteger */, 1, 4, v32)
		case float64:
			p, err = cmd.Call("CreateParameter", "", 5 /* adDouble */, 1, 8, v)
		case bool:
			p, err = cmd.Call("CreateParameter", "", 11 /* adBoolean */, 1, 1, v)
		case []byte:
			p, err = cmd.Call("CreateParameter", "", 8 /* adBSTR */, 1, len(v), string(v))
		case string:
			p, err = cmd.Call("CreateParameter", "", 8 /* adBSTR */, 1, len(v), v)
		case time.Time:
			p, err = cmd.Call("CreateParameter", "", 7 /* adDate */, 1, 8, v)
		default:
			err = fmt.Errorf("foxpro: parameters of type %T are not supported", a)
		}
		if err != nil {
			return nil, nil, err
		}
		param := p.(*com.IDispatch)
		defer param.Release()
		_, err = params.Call("Append", param)
		if err != nil {
			return nil, nil, err
		}
	}

	var nRecords int32
	x, err = cmd.Call("Execute", &nRecords)
	if err != nil {
		return nil, nil, err
	}
	recordset := x.(*com.IDispatch)
	return &rows{recordset}, driver.RowsAffected(nRecords), nil
}

type rows struct {
	rs *com.IDispatch
}

func (r *rows) Columns() []string {
	x, err := r.rs.Get("Fields")
	if err != nil {
		panic(err)
	}
	fields := x.(*com.IDispatch)
	defer fields.Release()

	x, err = fields.Get("Count")
	if err != nil {
		panic(err)
	}
	n := x.(int32)

	cols := make([]string, n)
	for i := int32(0); i < n; i++ {
		x, err = fields.Call("Item", i)
		if err != nil {
			panic(err)
		}
		item := x.(*com.IDispatch)
		defer item.Release()

		x, err = item.Get("Name")
		if err != nil {
			panic(err)
		}
		cols[i] = x.(string)
	}
	return cols
}

func (r *rows) Close() error {
	r.rs.Release()
	r.rs = nil
	return nil
}

func (r *rows) Next(dest []driver.Value) error {
	x, err := r.rs.Get("EOF")
	if err != nil {
		return err
	}
	if x == true {
		return io.EOF
	}

	x, err = r.rs.Get("Fields")
	if err != nil {
		return err
	}
	fields := x.(*com.IDispatch)
	defer fields.Release()

	for i := range dest {
		x, err = fields.Call("Item", int32(i))
		if err != nil {
			return err
		}
		item := x.(*com.IDispatch)
		defer item.Release()

		x, err = item.Get("Value")
		if err != nil {
			return err
		}
		switch v := x.(type) {
		case string:
			dest[i] = strings.TrimRight(v, " ")
		case int32:
			dest[i] = int64(v)
		case bool:
			dest[i] = v
		case com.Decimal:
			dest[i] = v.String()
		case time.Time:
			dest[i] = v
		case float64:
			dest[i] = v
		case nil:
			dest[i] = nil
		case com.Variant:
			return fmt.Errorf("foxpro: result variant with VT=%d not supported yet", v.VT)
		default:
			return fmt.Errorf("foxpro: result type %T not supported yet", v)
		}
	}

	_, err = r.rs.Call("MoveNext")
	if err != nil {
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>package prompt

import (
	// Stdlib
	"bufio"
	"errors"
	"fmt"
	"io"
	"os"
	"strconv"
	"strings"
	"text/tabwriter"

	// Internal
	"github.com/salsita/salsaflow/errs"
	"github.com/salsita/salsaflow/modules/common"

	// Other
	"gopkg.in/salsita/go-pivotaltracker.v0/v5/pivotal"
)

// maxStoryTitleColumnWidth specifies the width of the story title column for story listing.
// The story title is truncated to this width in case it is too long.
const maxStoryTitleColumnWidth = 80

type InvalidInputError struct {
	input string
}

func (i *InvalidInputError) Error() string {
	return "Invalid input: " + i.input
}

type OutOfBoundsError struct {
	input string
}

func (i *OutOfBoundsError) Error() string {
	return "Index out of bounds: " + i.input
}

func Confirm(question string) (bool, error) {
	printQuestion := func() {
		fmt.Print(question)
		fmt.Print(" [y/N]: ")
	}
	printQuestion()

	var line string
	scanner := bufio.NewScanner(os.Stdin)
	for scanner.Scan() {
		line = strings.ToLower(scanner.Text())
		switch line {
		case "":
			line = "n"
		case "y":
		case "n":
		default:
			printQuestion()
			continue
		}
		break
	}
	if err := scanner.Err(); err != nil {
		return false, err
	}

	return line == "y", nil
}

func Prompt(msg string) (string, error) {
	fmt.Print(msg)
	scanner := bufio.NewScanner(os.Stdin)
	scanner.Scan()
	if err := scanner.Err(); err != nil {
		return "", err
	}
	return scanner.Text(), nil
}

func PromptIndex(msg string, min, max int) (int, error) {
	line, err := Prompt(msg)
	if err != nil {
		return 0, err
	}
	if line == "" {
		return 0, ErrCanceled
	}

	index, err := strconv.Atoi(line)
	if err != nil {
		return 0, &InvalidInputError{line}
	}

	if index < min || index > max {
		return 0, &OutOfBoundsError{line}
	}

	return index, nil
}

func PromptStory(msg string, stories []common.Story) (common.Story, error) {
	var task = "Prompt the user to select a story"

	// Make sure there are actually some stories to be printed.
	if len(stories) == 0 {
		fmt.Println("There are no stories to choose from!")
		return nil, errs.NewError(task, errors.New("no stories to be offered"), nil)
	}

	// Print the intro message.
	fmt.Println(msg)
	fmt.Println()

	// Present the stories to the user.
	if err := ListStories(stories, os.Stdout); err != nil {
		return nil, err
	}
	fmt.Println()

	// Prompt the user to select a story to assign the commit with.
	index, err := PromptIndex("Choose a story by inserting its index: ", 0, len(stories)-1)
	if err != nil {
		if err == ErrCanceled {
			return nil, ErrCanceled
		}
		return nil, errs.NewError(task, err, nil)
	}
	return stories[index], nil
}

func ConfirmStories(headerLine string, stories []*pivotal.Story) (bool, error) {
	printStoriesConfirmationDialog(headerLine, stories)

	var line string
	scanner := bufio.NewScanner(os.Stdin)
	for scanner.Scan() {
		line = strings.ToLower(scanner.Text())
		switch line {
		case "":
			line = "n"
		case "y":
		case "n":
		default:
			printStoriesConfirmationDialog(headerLine, stories)
			continue
		}
		break
	}
	if err := scanner.Err(); err != nil {
		return false, err
	}

	return line == "y", nil
}

func ListStories(stories []common.Story, w io.Writer) (err error) {
	var panicString = "_WRITE_PANIC_"

	must := func(n int, err error) {
		if err != nil {
			panic(panicString)
		}
	}

	defer func() {
		if r := recover(); r != nil {
			if str, ok := r.(string); ok && str == panicString {
				err = errors.New("failed to write to stdout")
			} else {
				panic(r)
			}
		}
	}()

	tw := tabwriter.NewWriter(w, 0, 8, 4, '\t', 0)
	must(io.WriteString(tw, "  Index\tStory ID\tStory Title\n"))
	must(io.WriteString(tw, "  =====\t========\t===========\n"))
	for i, story := range stories {
		must(fmt.Fprintf(
			tw, "  %v\t%v\t%v\n", i, story.ReadableId(), formatStoryTitle(story.Title())))
	}
	must(0, tw.Flush())

	return nil
}

func printStoriesConfirmationDialog(headerLine string, stories []*pivotal.Story) {
	tw := tabwriter.NewWriter(os.Stdout, 0, 8, 2, '\t', 0)

	io.WriteString(tw, "\n")
	io.WriteString(tw, headerLine)
	io.WriteString(tw, "\n\n")
	io.WriteString(tw, "Story Name\tStory URL\n")
	io.WriteString(tw, "==========\t=========\n")

	for _, story := range stories {
		fmt.Fprintf(tw, "%v\t%v\n", story.Name, story.URL)
	}

	io.WriteString(tw, "\nDo you want to proceed? [y/N]:")
	tw.Flush()
}

func formatStoryTitle(title string) string {
	if len(title) < maxStoryTitleColumnWidth {
		return title
	}

	// maxStoryTitleColumnWidth incorporates the trailing " ...",
	// so that is why we subtract len(" ...") when truncating.
	truncatedTitle := title[:maxStoryTitleColumnWidth-4]
	if title[maxStoryTitleColumnWidth-4] != ' ' {
		if i := strings.LastIndex(truncatedTitle, " "); i != -1 {
			truncatedTitle = truncatedTitle[:i]
		}
	}
	return truncatedTitle + " ..."
}
<commit_msg>prompt: Fix wrong error string<commit_after>package prompt

import (
	// Stdlib
	"bufio"
	"errors"
	"fmt"
	"io"
	"os"
	"strconv"
	"strings"
	"text/tabwriter"

	// Internal
	"github.com/salsita/salsaflow/errs"
	"github.com/salsita/salsaflow/modules/common"

	// Other
	"gopkg.in/salsita/go-pivotaltracker.v0/v5/pivotal"
)

// maxStoryTitleColumnWidth specifies the width of the story title column for story listing.
// The story title is truncated to this width in case it is too long.
const maxStoryTitleColumnWidth = 80

type InvalidInputError struct {
	input string
}

func (i *InvalidInputError) Error() string {
	return "Invalid input: " + i.input
}

type OutOfBoundsError struct {
	input string
}

func (i *OutOfBoundsError) Error() string {
	return "Index out of bounds: " + i.input
}

func Confirm(question string) (bool, error) {
	printQuestion := func() {
		fmt.Print(question)
		fmt.Print(" [y/N]: ")
	}
	printQuestion()

	var line string
	scanner := bufio.NewScanner(os.Stdin)
	for scanner.Scan() {
		line = strings.ToLower(scanner.Text())
		switch line {
		case "":
			line = "n"
		case "y":
		case "n":
		default:
			printQuestion()
			continue
		}
		break
	}
	if err := scanner.Err(); err != nil {
		return false, err
	}

	return line == "y", nil
}

func Prompt(msg string) (string, error) {
	fmt.Print(msg)
	scanner := bufio.NewScanner(os.Stdin)
	scanner.Scan()
	if err := scanner.Err(); err != nil {
		return "", err
	}
	return scanner.Text(), nil
}

func PromptIndex(msg string, min, max int) (int, error) {
	line, err := Prompt(msg)
	if err != nil {
		return 0, err
	}
	if line == "" {
		return 0, ErrCanceled
	}

	index, err := strconv.Atoi(line)
	if err != nil {
		return 0, &InvalidInputError{line}
	}

	if index < min || index > max {
		return 0, &OutOfBoundsError{line}
	}

	return index, nil
}

func PromptStory(msg string, stories []common.Story) (common.Story, error) {
	var task = "Prompt the user to select a story"

	// Make sure there are actually some stories to be printed.
	if len(stories) == 0 {
		fmt.Println("There are no stories to choose from!")
		return nil, errs.NewError(task, errors.New("no stories to be offered"), nil)
	}

	// Print the intro message.
	fmt.Println(msg)
	fmt.Println()

	// Present the stories to the user.
	if err := ListStories(stories, os.Stdout); err != nil {
		return nil, err
	}
	fmt.Println()

	// Prompt the user to select a story to assign the commit with.
	index, err := PromptIndex("Choose a story by inserting its index: ", 0, len(stories)-1)
	if err != nil {
		if err == ErrCanceled {
			return nil, ErrCanceled
		}
		return nil, errs.NewError(task, err, nil)
	}
	return stories[index], nil
}

func ConfirmStories(headerLine string, stories []*pivotal.Story) (bool, error) {
	printStoriesConfirmationDialog(headerLine, stories)

	var line string
	scanner := bufio.NewScanner(os.Stdin)
	for scanner.Scan() {
		line = strings.ToLower(scanner.Text())
		switch line {
		case "":
			line = "n"
		case "y":
		case "n":
		default:
			printStoriesConfirmationDialog(headerLine, stories)
			continue
		}
		break
	}
	if err := scanner.Err(); err != nil {
		return false, err
	}

	return line == "y", nil
}

type writeError struct {
	err error
}

func ListStories(stories []common.Story, w io.Writer) (err error) {
	must := func(n int, err error) {
		if err != nil {
			panic(&writeError{err})
		}
	}

	defer func() {
		if r := recover(); r != nil {
			if we, ok := r.(*writeError); ok {
				err = we.err
			} else {
				panic(r)
			}
		}
	}()

	tw := tabwriter.NewWriter(w, 0, 8, 4, '\t', 0)
	must(io.WriteString(tw, "  Index\tStory ID\tStory Title\n"))
	must(io.WriteString(tw, "  =====\t========\t===========\n"))
	for i, story := range stories {
		must(fmt.Fprintf(
			tw, "  %v\t%v\t%v\n", i, story.ReadableId(), formatStoryTitle(story.Title())))
	}
	must(0, tw.Flush())

	return nil
}

func printStoriesConfirmationDialog(headerLine string, stories []*pivotal.Story) {
	tw := tabwriter.NewWriter(os.Stdout, 0, 8, 2, '\t', 0)

	io.WriteString(tw, "\n")
	io.WriteString(tw, headerLine)
	io.WriteString(tw, "\n\n")
	io.WriteString(tw, "Story Name\tStory URL\n")
	io.WriteString(tw, "==========\t=========\n")

	for _, story := range stories {
		fmt.Fprintf(tw, "%v\t%v\n", story.Name, story.URL)
	}

	io.WriteString(tw, "\nDo you want to proceed? [y/N]:")
	tw.Flush()
}

func formatStoryTitle(title string) string {
	if len(title) < maxStoryTitleColumnWidth {
		return title
	}

	// maxStoryTitleColumnWidth incorporates the trailing " ...",
	// so that is why we subtract len(" ...") when truncating.
	truncatedTitle := title[:maxStoryTitleColumnWidth-4]
	if title[maxStoryTitleColumnWidth-4] != ' ' {
		if i := strings.LastIndex(truncatedTitle, " "); i != -1 {
			truncatedTitle = truncatedTitle[:i]
		}
	}
	return truncatedTitle + " ..."
}
<|endoftext|>