<commit_before>package local

import (
	"encoding/json"
	"io"
	"io/ioutil"
	"time"

	"github.com/fatih/structs"
	"github.com/inconshreveable/log15"
	"github.com/leeola/errors"
	"github.com/leeola/fixity"
	"github.com/leeola/fixity/fieldunmarshallers/mapfieldunmarshaller"
	"github.com/leeola/fixity/q"
)

type Config struct {
	Index    fixity.Index `toml:"-"`
	Store    fixity.Store `toml:"-"`
	Log      log15.Logger `toml:"-"`
	RootPath string       `toml:"rootPath"`
}

type Local struct {
	config Config
	index  fixity.Index
	store  fixity.Store
	log    log15.Logger
}

func New(c Config) (*Local, error) {
	if c.Index == nil {
		return nil, errors.New("missing reqired config: Index")
	}
	if c.Store == nil {
		return nil, errors.New("missing reqired config: Store")
	}

	if c.Log == nil {
		c.Log = log15.New()
	}

	return &Local{
		config: c,
		index:  c.Index,
		store:  c.Store,
		log:    c.Log,
	}, nil
}

func (l *Local) Blob(h string) ([]byte, error) {
	rc, err := l.store.Read(h)
	if err != nil {
		return nil, err
	}
	defer rc.Close()

	b, err := ioutil.ReadAll(rc)
	if err != nil {
		return nil, err
	}

	return b, nil
}

// makeFields created index Fields for the Version as well as unknown values.
func (l *Local) makeFields(version fixity.Version, multiJson fixity.MultiJson) (fixity.Fields, error) {
	// NOTE(leeola): The fieldUnmarshaller lazily unmarshals, so if all fields
	// are specified then no unmarshalling is needed.
	var fu *mapfieldunmarshaller.MapFieldUnmarshaller

	// TODO(leeola): this whole section is super hacky, ignoring support for
	// multiJson, not refactoring the usage until it compiles.
	var (
		jsonMeta *fixity.JsonMeta
		jsonHash string
	)
	for k, jsonWithMeta := range multiJson {
		fu = mapfieldunmarshaller.New([]byte(jsonWithMeta.JsonBytes))
		jsonMeta = jsonWithMeta.JsonMeta
		jsonHash = version.MultiJsonHash[k].JsonHash

		// TODO(leeola): make a new mapfieldunmarshaller that is constructed from
		// multiple other field unmarshallers. For now we're just using the first
		// json.. which is a temporary hack to get the refactoring back to "working".
		break
	}

	// copy the fields list so that we can add to it, without
	// modifying what is stored
	var indexFields fixity.Fields
	if jsonMeta != nil {
		indexFields = make(fixity.Fields, len(jsonMeta.IndexedFields))
		for i, f := range jsonMeta.IndexedFields {
			// NOTE(leeola): It's important that we don't modify the
			// version.JsonMeta.IndexedFields slice or we would end up storing values
			// twice when the caller didn't want that.
			if f.Value == nil {
				v, err := fu.Unmarshal(f.Field)
				if err != nil {
					return nil, err
				}
				f.Value = v
			}

			indexFields[i] = f
		}
	}

	indexFields.Append(fixity.Field{
		Field: "version.jsonHash",
		Value: jsonHash,
	})
	indexFields.Append(fixity.Field{
		Field: "version.multiBlobHash",
		Value: version.MultiBlobHash,
	})
	indexFields.Append(fixity.Field{
		Field: "version.id",
		Value: version.Id,
	})
	indexFields.Append(fixity.Field{
		Field: "version.uploadedAt",
		Value: version.UploadedAt,
	})
	indexFields.Append(fixity.Field{
		Field: "version.previousVersionCount",
		Value: version.PreviousVersionCount,
	})
	indexFields.Append(fixity.Field{
		Field: "version.previousVersionHash",
		Value: version.PreviousVersionHash,
	})

	return indexFields, nil
}

func (l *Local) ReadHash(h string) (fixity.Version, error) {
	var v fixity.Version
	if err := ReadAndUnmarshal(l.store, h, &v); err != nil {
		return fixity.Version{}, err
	}

	if structs.IsZero(v) {
		return fixity.Version{}, fixity.ErrNotVersion
	}

	for _, jhwm := range v.JsonHashWithMeta {
		if err := ReadAndUnmarshal(l.store, jhwm.JsonHash, &v.Json); err != nil {
			return fixity.Version{}, err
		}
	}

	if v.MultiBlobHash != "" {
		// TODO(leeola): Construct a new multiblob reader for the given hash.
		return fixity.Version{}, errors.New("multiBlob reading not yet supported")
	}

	return v, nil
}

func (l *Local) ReadId(id string) (fixity.Version, error) {
	// TODO(leeola): search the unique/id index for the given id,
	// but first i need to decide how the indexes are going to exactly
	// store the unique id versions.
	return fixity.Version{}, errors.New("not implemented")
}

func (l *Local) Write(c fixity.Commit, multiJson fixity.MultiJson, r io.Reader) ([]string, error) {
	// For quicker prototyping, only supporting metadata atm
	if r != nil {
		return nil, errors.New("reader not yet implemented")
	}

	if structs.IsZero(j) && r == nil {
		return nil, errors.New("No data given to write")
	}

	// the hashes we're going to return for the user.
	var hashes []string

	// marshal the given multijson to construct a multijsonhash.
	multiJsonHash := fixity.MultiJsonHash{}
	for k, jwm := range multiJson {
		jsonHash, err := MarshalAndWrite(l.store, jwm.Json)
		if err != nil {
			return nil, errors.Stack(err)
		}

		hashes = append(hashes, jsonHash)

		multiJsonHash[k] = fixity.JsonHashWithMeta{
			JsonWithMeta: jwm,
			JsonHash:     jsonHash,
		}
	}

	var multiBlobHash string
	// TODO(leeola): Make this into a multipart splitter.
	// For now it's disabled.
	//
	// multiBlobHash, err := store.WriteReader(l.store, r)
	// if err != nil {
	// return nil, errors.Stack(err)
	// }

	if c.Id != "" || c.PreviousVersionHash != "" {
		l.log.Warn("object mutation is not yet implemented",
			"id", c.Id, "previousVersionHash", c.PreviousVersionHash)
	}

	// TODO(leeola): construct a standard to allow writers leave the time
	// blank. Useful for making ID chains based off of history, and ignoring
	// time completely.
	if c.UploadedAt == nil {
		now := time.Now()
		c.UploadedAt = &now
	}

	version := fixity.Version{
		Id:                  c.Id,
		UploadedAt:          c.UploadedAt,
		PreviousVersionHash: c.PreviousVersionHash,
		ChangeLog:           c.ChangeLog,
		MultiJsonHash:       multiJsonHash,
		MultiBlobHash:       multiBlobHash,
	}

	// TODO(leeola): load the old version if previous version hash is specified
	// if c.PreviousVersionHash != "" {
	// // .. load previous hash
	// version = previousVersion
	// }

	versionHash, err := MarshalAndWrite(l.store, version)
	if err != nil {
		return nil, errors.Stack(err)
	}

	// TODO(leeola): Index the metadata now that all has been written to the store.

	// Replace the old changelog no matter what. Eg, even if we loaded an old version,
	// the old version's changelog doesn't apply to the new version, so replace it,
	// even if we're repalcing it with nothing.
	version.ChangeLog = c.ChangeLog

	indexFields, err := l.makeFields(version, multiJson)
	if err != nil {
		return nil, err
	}

	if err := l.index.Index(versionHash, version.Id, indexFields); err != nil {
		return nil, err
	}

	return append(hashes, versionHash), nil
}

func (l *Local) Search(q *q.Query) ([]string, error) {
	return l.index.Search(q)
}

// WriteReader writes the given reader's content to the store.
func WriteReader(s fixity.Store, r io.Reader) (string, error) {
	if s == nil {
		return "", errors.New("Store is nil")
	}
	if r == nil {
		return "", errors.New("Reader is nil")
	}

	b, err := ioutil.ReadAll(r)
	if err != nil {
		return "", errors.Wrap(err, "failed to readall")
	}

	h, err := s.Write(b)
	return h, errors.Wrap(err, "store failed to write")
}

// MarshalAndWrite marshals the given interface to json and writes that to the store.
func MarshalAndWrite(s fixity.Store, v interface{}) (string, error) {
	if s == nil {
		return "", errors.New("Store is nil")
	}
	if v == nil {
		return "", errors.New("Interface is nil")
	}

	b, err := json.Marshal(v)
	if err != nil {
		return "", errors.Stack(err)
	}

	h, err := s.Write(b)
	if err != nil {
		return "", errors.Stack(err)
	}

	return h, nil
}

func ReadAll(s fixity.Store, h string) ([]byte, error) {
	rc, err := s.Read(h)
	if err != nil {
		return nil, errors.Stack(err)
	}
	defer rc.Close()

	return ioutil.ReadAll(rc)
}

func ReadAndUnmarshal(s fixity.Store, h string, v interface{}) error {
	_, err := ReadAndUnmarshalWithBytes(s, h, v)
	return err
}

func ReadAndUnmarshalWithBytes(s fixity.Store, h string, v interface{}) ([]byte, error) {
	b, err := ReadAll(s, h)
	if err != nil {
		return nil, errors.Stack(err)
	}

	if err := json.Unmarshal(b, v); err != nil {
		return nil, errors.Stack(err)
	}

	return b, nil
}
<commit_msg>feat: lazily index multiple json structs<commit_after>package local

import (
	"encoding/json"
	"io"
	"io/ioutil"
	"time"

	"github.com/fatih/structs"
	"github.com/inconshreveable/log15"
	"github.com/leeola/errors"
	"github.com/leeola/fixity"
	"github.com/leeola/fixity/fieldunmarshallers/mapfieldunmarshaller"
	"github.com/leeola/fixity/q"
)

type Config struct {
	Index    fixity.Index `toml:"-"`
	Store    fixity.Store `toml:"-"`
	Log      log15.Logger `toml:"-"`
	RootPath string       `toml:"rootPath"`
}

type Local struct {
	config Config
	index  fixity.Index
	store  fixity.Store
	log    log15.Logger
}

func New(c Config) (*Local, error) {
	if c.Index == nil {
		return nil, errors.New("missing reqired config: Index")
	}
	if c.Store == nil {
		return nil, errors.New("missing reqired config: Store")
	}

	if c.Log == nil {
		c.Log = log15.New()
	}

	return &Local{
		config: c,
		index:  c.Index,
		store:  c.Store,
		log:    c.Log,
	}, nil
}

func (l *Local) Blob(h string) ([]byte, error) {
	rc, err := l.store.Read(h)
	if err != nil {
		return nil, err
	}
	defer rc.Close()

	b, err := ioutil.ReadAll(rc)
	if err != nil {
		return nil, err
	}

	return b, nil
}

// makeFields created index Fields for the Version as well as unknown values.
func (l *Local) makeFields(version fixity.Version, multiJson fixity.MultiJson) (fixity.Fields, error) {
	var (
		jsonHashes  []string
		indexFields fixity.Fields
	)
	for _, jsonHashWithMeta := range version.MultiJsonHash {
		// the embedded JsonWithMeta value prior to writing *does* contain the
		// Json bytes. After writing, it does not. In other words, we can get the
		// JsonWithMeta from the JsonHashWithMeta prior to writing, and only
		// prior to writing.
		jsonWithMeta := jsonHashWithMeta.JsonWithMeta

		// Note that we could make this more efficient by using
		// make([]string, len(jsonHashWithMeta)), but then we have to keep a tally
		// of the index that this map range is on. I'm just choosing not to,
		// currently.
		jsonHashes = append(jsonHashes, jsonHashWithMeta.JsonHash)

		if jsonWithMeta.JsonMeta != nil {
			// NOTE(leeola): The fieldUnmarshaller lazily unmarshals, so if all fields
			// are specified then no unmarshalling is needed.
			//
			// This is only not nil if a value is missing from an index field.
			// It also caches the unmarshalling process.
			var u *mapfieldunmarshaller.MapFieldUnmarshaller

			for _, f := range jsonWithMeta.JsonMeta.IndexedFields {
				if f.Value == nil {
					// only instantiate the field unmarshaller as needed.
					if u == nil {
						u = mapfieldunmarshaller.New([]byte(jsonWithMeta.JsonBytes))
					}

					v, err := u.Unmarshal(f.Field)
					if err != nil {
						return nil, err
					}
					f.Value = v
				}

				indexFields = append(indexFields, f)
			}
		}
	}

	indexFields.Append(fixity.Field{
		Field: "version.jsonHashes",
		Value: jsonHashes,
	})
	indexFields.Append(fixity.Field{
		Field: "version.multiBlobHash",
		Value: version.MultiBlobHash,
	})
	indexFields.Append(fixity.Field{
		Field: "version.id",
		Value: version.Id,
	})
	indexFields.Append(fixity.Field{
		Field: "version.uploadedAt",
		Value: version.UploadedAt,
	})
	indexFields.Append(fixity.Field{
		Field: "version.previousVersionCount",
		Value: version.PreviousVersionCount,
	})
	indexFields.Append(fixity.Field{
		Field: "version.previousVersionHash",
		Value: version.PreviousVersionHash,
	})

	return indexFields, nil
}

func (l *Local) ReadHash(h string) (fixity.Version, error) {
	var v fixity.Version
	if err := ReadAndUnmarshal(l.store, h, &v); err != nil {
		return fixity.Version{}, err
	}

	if structs.IsZero(v) {
		return fixity.Version{}, fixity.ErrNotVersion
	}

	for _, jhwm := range v.JsonHashWithMeta {
		if err := ReadAndUnmarshal(l.store, jhwm.JsonHash, &v.Json); err != nil {
			return fixity.Version{}, err
		}
	}

	if v.MultiBlobHash != "" {
		// TODO(leeola): Construct a new multiblob reader for the given hash.
		return fixity.Version{}, errors.New("multiBlob reading not yet supported")
	}

	return v, nil
}

func (l *Local) ReadId(id string) (fixity.Version, error) {
	// TODO(leeola): search the unique/id index for the given id,
	// but first i need to decide how the indexes are going to exactly
	// store the unique id versions.
	return fixity.Version{}, errors.New("not implemented")
}

func (l *Local) Write(c fixity.Commit, multiJson fixity.MultiJson, r io.Reader) ([]string, error) {
	// For quicker prototyping, only supporting metadata atm
	if r != nil {
		return nil, errors.New("reader not yet implemented")
	}

	if structs.IsZero(j) && r == nil {
		return nil, errors.New("No data given to write")
	}

	// the hashes we're going to return for the user.
	var hashes []string

	// marshal the given multijson to construct a multijsonhash.
	multiJsonHash := fixity.MultiJsonHash{}
	for k, jwm := range multiJson {
		jsonHash, err := MarshalAndWrite(l.store, jwm.Json)
		if err != nil {
			return nil, errors.Stack(err)
		}

		hashes = append(hashes, jsonHash)

		multiJsonHash[k] = fixity.JsonHashWithMeta{
			JsonWithMeta: jwm,
			JsonHash:     jsonHash,
		}
	}

	var multiBlobHash string
	// TODO(leeola): Make this into a multipart splitter.
	// For now it's disabled.
	//
	// multiBlobHash, err := store.WriteReader(l.store, r)
	// if err != nil {
	// return nil, errors.Stack(err)
	// }

	if c.Id != "" || c.PreviousVersionHash != "" {
		l.log.Warn("object mutation is not yet implemented",
			"id", c.Id, "previousVersionHash", c.PreviousVersionHash)
	}

	// TODO(leeola): construct a standard to allow writers leave the time
	// blank. Useful for making ID chains based off of history, and ignoring
	// time completely.
	if c.UploadedAt == nil {
		now := time.Now()
		c.UploadedAt = &now
	}

	version := fixity.Version{
		Id:                  c.Id,
		UploadedAt:          c.UploadedAt,
		PreviousVersionHash: c.PreviousVersionHash,
		ChangeLog:           c.ChangeLog,
		MultiJsonHash:       multiJsonHash,
		MultiBlobHash:       multiBlobHash,
	}

	// TODO(leeola): load the old version if previous version hash is specified
	// if c.PreviousVersionHash != "" {
	// // .. load previous hash
	// version = previousVersion
	// }

	versionHash, err := MarshalAndWrite(l.store, version)
	if err != nil {
		return nil, errors.Stack(err)
	}

	// TODO(leeola): Index the metadata now that all has been written to the store.

	// Replace the old changelog no matter what. Eg, even if we loaded an old version,
	// the old version's changelog doesn't apply to the new version, so replace it,
	// even if we're repalcing it with nothing.
	version.ChangeLog = c.ChangeLog

	indexFields, err := l.makeFields(version, multiJson)
	if err != nil {
		return nil, err
	}

	if err := l.index.Index(versionHash, version.Id, indexFields); err != nil {
		return nil, err
	}

	return append(hashes, versionHash), nil
}

func (l *Local) Search(q *q.Query) ([]string, error) {
	return l.index.Search(q)
}

// WriteReader writes the given reader's content to the store.
func WriteReader(s fixity.Store, r io.Reader) (string, error) {
	if s == nil {
		return "", errors.New("Store is nil")
	}
	if r == nil {
		return "", errors.New("Reader is nil")
	}

	b, err := ioutil.ReadAll(r)
	if err != nil {
		return "", errors.Wrap(err, "failed to readall")
	}

	h, err := s.Write(b)
	return h, errors.Wrap(err, "store failed to write")
}

// MarshalAndWrite marshals the given interface to json and writes that to the store.
func MarshalAndWrite(s fixity.Store, v interface{}) (string, error) {
	if s == nil {
		return "", errors.New("Store is nil")
	}
	if v == nil {
		return "", errors.New("Interface is nil")
	}

	b, err := json.Marshal(v)
	if err != nil {
		return "", errors.Stack(err)
	}

	h, err := s.Write(b)
	if err != nil {
		return "", errors.Stack(err)
	}

	return h, nil
}

func ReadAll(s fixity.Store, h string) ([]byte, error) {
	rc, err := s.Read(h)
	if err != nil {
		return nil, errors.Stack(err)
	}
	defer rc.Close()

	return ioutil.ReadAll(rc)
}

func ReadAndUnmarshal(s fixity.Store, h string, v interface{}) error {
	_, err := ReadAndUnmarshalWithBytes(s, h, v)
	return err
}

func ReadAndUnmarshalWithBytes(s fixity.Store, h string, v interface{}) ([]byte, error) {
	b, err := ReadAll(s, h)
	if err != nil {
		return nil, errors.Stack(err)
	}

	if err := json.Unmarshal(b, v); err != nil {
		return nil, errors.Stack(err)
	}

	return b, nil
}
<|endoftext|>


<commit_before>package importer

// TODO(gri): absorb this into go/types.

import (
	"code.google.com/p/go.tools/go/exact"
	"code.google.com/p/go.tools/go/types"
	"go/ast"
	"go/token"
	"strconv"
)

// PackageInfo holds the ASTs and facts derived by the type-checker
// for a single package.
//
// Not mutated once constructed.
//
type PackageInfo struct {
	Pkg   *types.Package
	Files []*ast.File // abstract syntax for the package's files

	// Type-checker deductions.
	types     map[ast.Expr]types.Type        // inferred types of expressions
	constants map[ast.Expr]exact.Value       // values of constant expressions
	idents    map[*ast.Ident]types.Object    // resolved objects for named entities
	typecases map[*ast.CaseClause]*types.Var // implicit vars for single-type typecases
}

// Imports returns the set of packages imported by this one, in source
// order.  Callers should not mutate the result.
//
func (info *PackageInfo) Imports() []*types.Package {
	var imports []*types.Package

	// We iterate over the syntax (info.Files) not the types
	// (info.Pkg.Imports()) because the latter may contain the
	// transitive closure of dependencies, e.g. when using GcImporter.
	seen := make(map[*types.Package]bool)
	for _, file := range info.Files {
		for _, imp := range file.Imports {
			path, _ := strconv.Unquote(imp.Path.Value)
			if path == "unsafe" {
				continue // not a true package
			}
			typkg := info.Pkg.Imports()[path]
			if seen[typkg] {
				continue // already seen
			}
			seen[typkg] = true
			imports = append(imports, typkg)
		}
	}
	return imports
}

// TypeOf returns the type of expression e.
// Precondition: e belongs to the package's ASTs.
//
func (info *PackageInfo) TypeOf(e ast.Expr) types.Type {
	// For Ident, b.types may be more specific than
	// b.obj(id.(*ast.Ident)).GetType(),
	// e.g. in the case of typeswitch.
	if t, ok := info.types[e]; ok {
		return t
	}
	// The typechecker doesn't notify us of all Idents,
	// e.g. s.Key and s.Value in a RangeStmt.
	// So we have this fallback.
	// TODO(gri): This is a typechecker bug.  When fixed,
	// eliminate this case and panic.
	if id, ok := e.(*ast.Ident); ok {
		return info.ObjectOf(id).Type()
	}
	panic("no type for expression")
}

// ValueOf returns the value of expression e if it is a constant, nil
// otherwise.
// Precondition: e belongs to the package's ASTs.
//
func (info *PackageInfo) ValueOf(e ast.Expr) exact.Value {
	return info.constants[e]
}

// ObjectOf returns the typechecker object denoted by the specified id.
// Precondition: id belongs to the package's ASTs.
//
func (info *PackageInfo) ObjectOf(id *ast.Ident) types.Object {
	return info.idents[id]
}

// IsType returns true iff expression e denotes a type.
// Precondition: e belongs to the package's ASTs.
// e must be a true expression, not a KeyValueExpr, or an Ident
// appearing in a SelectorExpr or declaration.
//
func (info *PackageInfo) IsType(e ast.Expr) bool {
	switch e := e.(type) {
	case *ast.SelectorExpr: // pkg.Type
		if obj := info.IsPackageRef(e); obj != nil {
			_, isType := obj.(*types.TypeName)
			return isType
		}
	case *ast.StarExpr: // *T
		return info.IsType(e.X)
	case *ast.Ident:
		_, isType := info.ObjectOf(e).(*types.TypeName)
		return isType
	case *ast.ArrayType, *ast.StructType, *ast.FuncType, *ast.InterfaceType, *ast.MapType, *ast.ChanType:
		return true
	case *ast.ParenExpr:
		return info.IsType(e.X)
	}
	return false
}

// IsPackageRef returns the identity of the object if sel is a
// package-qualified reference to a named const, var, func or type.
// Otherwise it returns nil.
// Precondition: sel belongs to the package's ASTs.
//
func (info *PackageInfo) IsPackageRef(sel *ast.SelectorExpr) types.Object {
	if id, ok := sel.X.(*ast.Ident); ok {
		if pkg, ok := info.ObjectOf(id).(*types.Package); ok {
			return pkg.Scope().Lookup(nil, sel.Sel.Name)
		}
	}
	return nil
}

// TypeCaseVar returns the implicit variable created by a single-type
// case clause in a type switch, or nil if not found.
//
func (info *PackageInfo) TypeCaseVar(cc *ast.CaseClause) *types.Var {
	return info.typecases[cc]
}

var (
	tEface      = new(types.Interface)
	tComplex64  = types.Typ[types.Complex64]
	tComplex128 = types.Typ[types.Complex128]
	tFloat32    = types.Typ[types.Float32]
	tFloat64    = types.Typ[types.Float64]
)

// BuiltinCallSignature returns a new Signature describing the
// effective type of a builtin operator for the particular call e.
//
// This requires ad-hoc typing rules for all variadic (append, print,
// println) and polymorphic (append, copy, delete, close) built-ins.
// This logic could be part of the typechecker, and should arguably
// be moved there and made accessible via an additional types.Context
// callback.
//
// The returned Signature is degenerate and only intended for use by
// emitCallArgs.
//
func (info *PackageInfo) BuiltinCallSignature(e *ast.CallExpr) *types.Signature {
	var params []*types.Var
	var isVariadic bool

	switch builtin := unparen(e.Fun).(*ast.Ident).Name; builtin {
	case "append":
		var t0, t1 types.Type
		t0 = info.TypeOf(e) // infer arg[0] type from result type
		if e.Ellipsis != 0 {
			// append([]T, []T) []T
			// append([]byte, string) []byte
			t1 = info.TypeOf(e.Args[1]) // no conversion
		} else {
			// append([]T, ...T) []T
			t1 = t0.Underlying().(*types.Slice).Elem()
			isVariadic = true
		}
		params = append(params,
			types.NewVar(token.NoPos, nil, "", t0),
			types.NewVar(token.NoPos, nil, "", t1))

	case "print", "println": // print{,ln}(any, ...interface{})
		isVariadic = true
		// Note, arg0 may have any type, not necessarily tEface.
		params = append(params,
			types.NewVar(token.NoPos, nil, "", info.TypeOf(e.Args[0])),
			types.NewVar(token.NoPos, nil, "", tEface))

	case "close":
		params = append(params, types.NewVar(token.NoPos, nil, "", info.TypeOf(e.Args[0])))

	case "copy":
		// copy([]T, []T) int
		// Infer arg types from each other.  Sleazy.
		var st *types.Slice
		if t, ok := info.TypeOf(e.Args[0]).Underlying().(*types.Slice); ok {
			st = t
		} else if t, ok := info.TypeOf(e.Args[1]).Underlying().(*types.Slice); ok {
			st = t
		} else {
			panic("cannot infer types in call to copy()")
		}
		stvar := types.NewVar(token.NoPos, nil, "", st)
		params = append(params, stvar, stvar)

	case "delete":
		// delete(map[K]V, K)
		tmap := info.TypeOf(e.Args[0])
		tkey := tmap.Underlying().(*types.Map).Key()
		params = append(params,
			types.NewVar(token.NoPos, nil, "", tmap),
			types.NewVar(token.NoPos, nil, "", tkey))

	case "len", "cap":
		params = append(params, types.NewVar(token.NoPos, nil, "", info.TypeOf(e.Args[0])))

	case "real", "imag":
		// Reverse conversion to "complex" case below.
		var argType types.Type
		switch info.TypeOf(e).(*types.Basic).Kind() {
		case types.UntypedFloat:
			argType = types.Typ[types.UntypedComplex]
		case types.Float64:
			argType = tComplex128
		case types.Float32:
			argType = tComplex64
		default:
			unreachable()
		}
		params = append(params, types.NewVar(token.NoPos, nil, "", argType))

	case "complex":
		var argType types.Type
		switch info.TypeOf(e).(*types.Basic).Kind() {
		case types.UntypedComplex:
			argType = types.Typ[types.UntypedFloat]
		case types.Complex128:
			argType = tFloat64
		case types.Complex64:
			argType = tFloat32
		default:
			unreachable()
		}
		v := types.NewVar(token.NoPos, nil, "", argType)
		params = append(params, v, v)

	case "panic":
		params = append(params, types.NewVar(token.NoPos, nil, "", tEface))

	case "recover":
		// no params

	default:
		panic("unknown builtin: " + builtin)
	}

	return types.NewSignature(nil, types.NewTuple(params...), nil, isVariadic)
}
<commit_msg>go.tools/importer: update comment (and absolve gri of blame) for non-bug.<commit_after>package importer

// TODO(gri): absorb this into go/types.

import (
	"code.google.com/p/go.tools/go/exact"
	"code.google.com/p/go.tools/go/types"
	"go/ast"
	"go/token"
	"strconv"
)

// PackageInfo holds the ASTs and facts derived by the type-checker
// for a single package.
//
// Not mutated once constructed.
//
type PackageInfo struct {
	Pkg   *types.Package
	Files []*ast.File // abstract syntax for the package's files

	// Type-checker deductions.
	types     map[ast.Expr]types.Type        // inferred types of expressions
	constants map[ast.Expr]exact.Value       // values of constant expressions
	idents    map[*ast.Ident]types.Object    // resolved objects for named entities
	typecases map[*ast.CaseClause]*types.Var // implicit vars for single-type typecases
}

// Imports returns the set of packages imported by this one, in source
// order.  Callers should not mutate the result.
//
func (info *PackageInfo) Imports() []*types.Package {
	var imports []*types.Package

	// We iterate over the syntax (info.Files) not the types
	// (info.Pkg.Imports()) because the latter may contain the
	// transitive closure of dependencies, e.g. when using GcImporter.
	seen := make(map[*types.Package]bool)
	for _, file := range info.Files {
		for _, imp := range file.Imports {
			path, _ := strconv.Unquote(imp.Path.Value)
			if path == "unsafe" {
				continue // not a true package
			}
			typkg := info.Pkg.Imports()[path]
			if seen[typkg] {
				continue // already seen
			}
			seen[typkg] = true
			imports = append(imports, typkg)
		}
	}
	return imports
}

// TypeOf returns the type of expression e.
// Precondition: e belongs to the package's ASTs.
//
func (info *PackageInfo) TypeOf(e ast.Expr) types.Type {
	if t, ok := info.types[e]; ok {
		return t
	}
	// Defining ast.Idents (id := expr) get only Ident callbacks
	// but not Expr callbacks.
	if id, ok := e.(*ast.Ident); ok {
		return info.ObjectOf(id).Type()
	}
	panic("no type for expression")
}

// ValueOf returns the value of expression e if it is a constant, nil
// otherwise.
// Precondition: e belongs to the package's ASTs.
//
func (info *PackageInfo) ValueOf(e ast.Expr) exact.Value {
	return info.constants[e]
}

// ObjectOf returns the typechecker object denoted by the specified id.
// Precondition: id belongs to the package's ASTs.
//
func (info *PackageInfo) ObjectOf(id *ast.Ident) types.Object {
	return info.idents[id]
}

// IsType returns true iff expression e denotes a type.
// Precondition: e belongs to the package's ASTs.
// e must be a true expression, not a KeyValueExpr, or an Ident
// appearing in a SelectorExpr or declaration.
//
func (info *PackageInfo) IsType(e ast.Expr) bool {
	switch e := e.(type) {
	case *ast.SelectorExpr: // pkg.Type
		if obj := info.IsPackageRef(e); obj != nil {
			_, isType := obj.(*types.TypeName)
			return isType
		}
	case *ast.StarExpr: // *T
		return info.IsType(e.X)
	case *ast.Ident:
		_, isType := info.ObjectOf(e).(*types.TypeName)
		return isType
	case *ast.ArrayType, *ast.StructType, *ast.FuncType, *ast.InterfaceType, *ast.MapType, *ast.ChanType:
		return true
	case *ast.ParenExpr:
		return info.IsType(e.X)
	}
	return false
}

// IsPackageRef returns the identity of the object if sel is a
// package-qualified reference to a named const, var, func or type.
// Otherwise it returns nil.
// Precondition: sel belongs to the package's ASTs.
//
func (info *PackageInfo) IsPackageRef(sel *ast.SelectorExpr) types.Object {
	if id, ok := sel.X.(*ast.Ident); ok {
		if pkg, ok := info.ObjectOf(id).(*types.Package); ok {
			return pkg.Scope().Lookup(nil, sel.Sel.Name)
		}
	}
	return nil
}

// TypeCaseVar returns the implicit variable created by a single-type
// case clause in a type switch, or nil if not found.
//
func (info *PackageInfo) TypeCaseVar(cc *ast.CaseClause) *types.Var {
	return info.typecases[cc]
}

var (
	tEface      = new(types.Interface)
	tComplex64  = types.Typ[types.Complex64]
	tComplex128 = types.Typ[types.Complex128]
	tFloat32    = types.Typ[types.Float32]
	tFloat64    = types.Typ[types.Float64]
)

// BuiltinCallSignature returns a new Signature describing the
// effective type of a builtin operator for the particular call e.
//
// This requires ad-hoc typing rules for all variadic (append, print,
// println) and polymorphic (append, copy, delete, close) built-ins.
// This logic could be part of the typechecker, and should arguably
// be moved there and made accessible via an additional types.Context
// callback.
//
// The returned Signature is degenerate and only intended for use by
// emitCallArgs.
//
func (info *PackageInfo) BuiltinCallSignature(e *ast.CallExpr) *types.Signature {
	var params []*types.Var
	var isVariadic bool

	switch builtin := unparen(e.Fun).(*ast.Ident).Name; builtin {
	case "append":
		var t0, t1 types.Type
		t0 = info.TypeOf(e) // infer arg[0] type from result type
		if e.Ellipsis != 0 {
			// append([]T, []T) []T
			// append([]byte, string) []byte
			t1 = info.TypeOf(e.Args[1]) // no conversion
		} else {
			// append([]T, ...T) []T
			t1 = t0.Underlying().(*types.Slice).Elem()
			isVariadic = true
		}
		params = append(params,
			types.NewVar(token.NoPos, nil, "", t0),
			types.NewVar(token.NoPos, nil, "", t1))

	case "print", "println": // print{,ln}(any, ...interface{})
		isVariadic = true
		// Note, arg0 may have any type, not necessarily tEface.
		params = append(params,
			types.NewVar(token.NoPos, nil, "", info.TypeOf(e.Args[0])),
			types.NewVar(token.NoPos, nil, "", tEface))

	case "close":
		params = append(params, types.NewVar(token.NoPos, nil, "", info.TypeOf(e.Args[0])))

	case "copy":
		// copy([]T, []T) int
		// Infer arg types from each other.  Sleazy.
		var st *types.Slice
		if t, ok := info.TypeOf(e.Args[0]).Underlying().(*types.Slice); ok {
			st = t
		} else if t, ok := info.TypeOf(e.Args[1]).Underlying().(*types.Slice); ok {
			st = t
		} else {
			panic("cannot infer types in call to copy()")
		}
		stvar := types.NewVar(token.NoPos, nil, "", st)
		params = append(params, stvar, stvar)

	case "delete":
		// delete(map[K]V, K)
		tmap := info.TypeOf(e.Args[0])
		tkey := tmap.Underlying().(*types.Map).Key()
		params = append(params,
			types.NewVar(token.NoPos, nil, "", tmap),
			types.NewVar(token.NoPos, nil, "", tkey))

	case "len", "cap":
		params = append(params, types.NewVar(token.NoPos, nil, "", info.TypeOf(e.Args[0])))

	case "real", "imag":
		// Reverse conversion to "complex" case below.
		var argType types.Type
		switch info.TypeOf(e).(*types.Basic).Kind() {
		case types.UntypedFloat:
			argType = types.Typ[types.UntypedComplex]
		case types.Float64:
			argType = tComplex128
		case types.Float32:
			argType = tComplex64
		default:
			unreachable()
		}
		params = append(params, types.NewVar(token.NoPos, nil, "", argType))

	case "complex":
		var argType types.Type
		switch info.TypeOf(e).(*types.Basic).Kind() {
		case types.UntypedComplex:
			argType = types.Typ[types.UntypedFloat]
		case types.Complex128:
			argType = tFloat64
		case types.Complex64:
			argType = tFloat32
		default:
			unreachable()
		}
		v := types.NewVar(token.NoPos, nil, "", argType)
		params = append(params, v, v)

	case "panic":
		params = append(params, types.NewVar(token.NoPos, nil, "", tEface))

	case "recover":
		// no params

	default:
		panic("unknown builtin: " + builtin)
	}

	return types.NewSignature(nil, types.NewTuple(params...), nil, isVariadic)
}
<|endoftext|>


<commit_before>package rkive

import (
	"testing"
)

func TestAddRemoveLink(t *testing.T) {
	info := Info{}

	info.AddLink("testlink", "testbucket", "k")

	bucket, key := info.GetLink("testlink")
	if bucket != "testbucket" || key != "k" {
		t.Errorf("Bucket: %q; key: %q", bucket, key)
	}

	info.RemoveLink("testlink")
	bucket, key = info.GetLink("testlink")
	if bucket != "" || key != "" {
		t.Errorf("Bucket: %q; key: %q", bucket, key)
	}

	info.AddLink("testlink", "testbucket", "k1")
	info.SetLink("testlink", "newbucket", "k2")

	bucket, key = info.GetLink("testlink")
	if bucket != "newbucket" || key != "k2" {
		t.Errorf("Bucket: %q; key: %q", bucket, key)
	}
}

func TestAddRemoveIndex(t *testing.T) {
	info := Info{}

	info.AddIndex("testidx", "blah")

	val := info.GetIndex("testidx")
	if val != "blah" {
		t.Errorf("Val: %q", val)
		t.Errorf("Indexes: %v", info.idxs)
	}

	info.SetIndex("testidx", "newblah")
	val = info.GetIndex("testidx")
	if val != "newblah" {
		t.Errorf("Val: %q", val)
	}

	info.RemoveIndex("testidx")
	val = info.GetIndex("testidx")
	if val != "" {
		t.Errorf("Val: %q", val)
	}

	info.AddIndexInt("myNum", 300)

	ival := info.GetIndexInt("myNum")
	if ival == nil || *ival != 300 {
		t.Errorf("Ival is %d; expected %d", *ival, 300)
	}

	info.SetIndexInt("myNum", -84)
	ival = info.GetIndexInt("myNum")
	if ival == nil || *ival != -84 {
		t.Errorf("Ival is %d; expected %d", *ival, -84)
	}

	info.RemoveIndexInt("myNum")
	ival = info.GetIndexInt("myNum")
	if ival != nil {
		t.Errorf("Expected nil; got %d", *ival)
	}
}
<commit_msg>test for client atomic field alignment<commit_after>package rkive

import (
	"testing"
	"unsafe"
)

func TestClientAlignment(t *testing.T) {
	// we're doing atomic operations
	// on 'conns', 'inuse', and 'tag', so
	// let's keep them 8-byte aligned

	cl := Client{}

	t.Logf("Client alignment: %d", unsafe.Alignof(cl))
	if (unsafe.Alignof(cl) % 8) != 0 {
		t.Errorf("Wanted 8-byte alignment; addr%8 = %d", unsafe.Alignof(cl)%8)
	}

	t.Logf("'conns' offset: %d", unsafe.Offsetof(cl.conns))
	if (unsafe.Offsetof(cl.conns) % 8) != 0 {
		t.Errorf("Wanted 8-byte alignment; addr%8 = %d", unsafe.Offsetof(cl.conns)%8)
	}

	t.Logf("'inuse' offset: %d", unsafe.Offsetof(cl.inuse))
	if (unsafe.Offsetof(cl.inuse) % 8) != 0 {
		t.Errorf("Wanted 8-byte alignment; addr%8 = %d", unsafe.Offsetof(cl.inuse)%8)
	}

	t.Logf("'tag' offset: %d", unsafe.Offsetof(cl.tag))
	if (unsafe.Offsetof(cl.tag) % 8) != 0 {
		t.Errorf("Wanted 8-byte alignment; addr%8 = %d", unsafe.Offsetof(cl.tag)%8)
	}

}

func TestAddRemoveLink(t *testing.T) {
	info := Info{}

	info.AddLink("testlink", "testbucket", "k")

	bucket, key := info.GetLink("testlink")
	if bucket != "testbucket" || key != "k" {
		t.Errorf("Bucket: %q; key: %q", bucket, key)
	}

	info.RemoveLink("testlink")
	bucket, key = info.GetLink("testlink")
	if bucket != "" || key != "" {
		t.Errorf("Bucket: %q; key: %q", bucket, key)
	}

	info.AddLink("testlink", "testbucket", "k1")
	info.SetLink("testlink", "newbucket", "k2")

	bucket, key = info.GetLink("testlink")
	if bucket != "newbucket" || key != "k2" {
		t.Errorf("Bucket: %q; key: %q", bucket, key)
	}
}

func TestAddRemoveIndex(t *testing.T) {
	info := Info{}

	info.AddIndex("testidx", "blah")

	val := info.GetIndex("testidx")
	if val != "blah" {
		t.Errorf("Val: %q", val)
		t.Errorf("Indexes: %v", info.idxs)
	}

	info.SetIndex("testidx", "newblah")
	val = info.GetIndex("testidx")
	if val != "newblah" {
		t.Errorf("Val: %q", val)
	}

	info.RemoveIndex("testidx")
	val = info.GetIndex("testidx")
	if val != "" {
		t.Errorf("Val: %q", val)
	}

	info.AddIndexInt("myNum", 300)

	ival := info.GetIndexInt("myNum")
	if ival == nil || *ival != 300 {
		t.Errorf("Ival is %d; expected %d", *ival, 300)
	}

	info.SetIndexInt("myNum", -84)
	ival = info.GetIndexInt("myNum")
	if ival == nil || *ival != -84 {
		t.Errorf("Ival is %d; expected %d", *ival, -84)
	}

	info.RemoveIndexInt("myNum")
	ival = info.GetIndexInt("myNum")
	if ival != nil {
		t.Errorf("Expected nil; got %d", *ival)
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.

package provider

import (
	"log"
)

const Version = "3.39.0"

func PrintVersion() {
	log.Printf("[INFO] terraform-provider-oci %s\n", Version)
}
<commit_msg>Finalize changelog and release for version v3.40.0<commit_after>// Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.

package provider

import (
	"log"
)

const Version = "3.40.0"

func PrintVersion() {
	log.Printf("[INFO] terraform-provider-oci %s\n", Version)
}
<|endoftext|>


<commit_before>// Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.

package provider

import (
	"log"
)

const Version = "3.8.0"

func PrintVersion() {
	log.Printf("[INFO] terraform-provider-oci %s\n", Version)
}
<commit_msg>Finalize changelog and release version (3.9.0)<commit_after>// Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.

package provider

import (
	"log"
)

const Version = "3.9.0"

func PrintVersion() {
	log.Printf("[INFO] terraform-provider-oci %s\n", Version)
}
<|endoftext|>


<commit_before>package vulcan

import (
	"encoding/json"
	"fmt"

	"github.com/mailgun/go-etcd/etcd"
)

const (
	etcdMachine   = "http://127.0.0.1:4001"
	frontendKey   = "%s/frontends/%s.%s/frontend"
	middlewareKey = "%s/frontends/%s.%s/middlewares/%s"
	backendKey    = "%s/backends/%s/backend"
	serverKey     = "%s/backends/%s/servers/%s"
)

type Client struct {
	Key  string
	etcd *etcd.Client
}

func NewClient(key string) *Client {
	etcd := etcd.NewClient([]string{etcdMachine})

	return &Client{Key: key, etcd: etcd}
}

func (c *Client) CreateServer(endpoint *Endpoint, ttl uint64) error {
	key := fmt.Sprintf(serverKey, c.Key, endpoint.Name, endpoint.ID)
	server, err := endpoint.ServerSpec()
	if err != nil {
		return nil
	}

	_, err = c.etcd.Create(key, server, ttl)
	if err != nil {
		return err
	}

	return nil
}

func (c *Client) UpdateServer(endpoint *Endpoint, ttl uint64) error {
	key := fmt.Sprintf(serverKey, c.Key, endpoint.Name, endpoint.ID)
	server, err := endpoint.ServerSpec()
	if err != nil {
		return nil
	}

	_, err = c.etcd.CompareAndSwap(key, server, ttl, server, 0)
	if err != nil {
		return err
	}

	return nil
}

func (c *Client) UpsertServer(endpoint *Endpoint, ttl uint64) error {
	key := fmt.Sprintf(serverKey, c.Key, endpoint.Name, endpoint.ID)
	server, err := endpoint.ServerSpec()
	if err != nil {
		return nil
	}

	_, err = c.etcd.Set(key, server, ttl)
	if err != nil {
		return err
	}

	return nil
}

func (c *Client) RegisterBackend(endpoint *Endpoint) error {
	key := fmt.Sprintf(backendKey, c.Key, endpoint.Name)
	backend, err := endpoint.BackendSpec()
	if err != nil {
		return err
	}

	_, err = c.etcd.Set(key, backend, 0)
	if err != nil {
		return err
	}

	return err
}

func (c *Client) RegisterFrontend(location *Location) error {
	key := fmt.Sprintf(frontendKey, c.Key, location.Host, location.ID)
	fmt.Println(location.ID)

	frontend, err := location.Spec()
	if err != nil {
		return err
	}

	_, err = c.etcd.Set(key, frontend, 0)
	if err != nil {
		return err
	}

	return nil
}

func (c *Client) RegisterMiddleware(location *Location) error {
	for i, m := range location.Middlewares {
		m.Priority = i

		key := fmt.Sprintf(middlewareKey, c.Key, location.Host, location.ID, m.ID)
		middleware, err := json.Marshal(m)
		if err != nil {
			return err
		}

		_, err = c.etcd.Set(key, string(middleware), 0)
		if err != nil {
			return err
		}
	}

	return nil
}
<commit_msg>Remove Println call.<commit_after>package vulcan

import (
	"encoding/json"
	"fmt"

	"github.com/mailgun/go-etcd/etcd"
)

const (
	etcdMachine   = "http://127.0.0.1:4001"
	frontendKey   = "%s/frontends/%s.%s/frontend"
	middlewareKey = "%s/frontends/%s.%s/middlewares/%s"
	backendKey    = "%s/backends/%s/backend"
	serverKey     = "%s/backends/%s/servers/%s"
)

type Client struct {
	Key  string
	etcd *etcd.Client
}

func NewClient(key string) *Client {
	etcd := etcd.NewClient([]string{etcdMachine})

	return &Client{Key: key, etcd: etcd}
}

func (c *Client) CreateServer(endpoint *Endpoint, ttl uint64) error {
	key := fmt.Sprintf(serverKey, c.Key, endpoint.Name, endpoint.ID)
	server, err := endpoint.ServerSpec()
	if err != nil {
		return nil
	}

	_, err = c.etcd.Create(key, server, ttl)
	if err != nil {
		return err
	}

	return nil
}

func (c *Client) UpdateServer(endpoint *Endpoint, ttl uint64) error {
	key := fmt.Sprintf(serverKey, c.Key, endpoint.Name, endpoint.ID)
	server, err := endpoint.ServerSpec()
	if err != nil {
		return nil
	}

	_, err = c.etcd.CompareAndSwap(key, server, ttl, server, 0)
	if err != nil {
		return err
	}

	return nil
}

func (c *Client) UpsertServer(endpoint *Endpoint, ttl uint64) error {
	key := fmt.Sprintf(serverKey, c.Key, endpoint.Name, endpoint.ID)
	server, err := endpoint.ServerSpec()
	if err != nil {
		return nil
	}

	_, err = c.etcd.Set(key, server, ttl)
	if err != nil {
		return err
	}

	return nil
}

func (c *Client) RegisterBackend(endpoint *Endpoint) error {
	key := fmt.Sprintf(backendKey, c.Key, endpoint.Name)
	backend, err := endpoint.BackendSpec()
	if err != nil {
		return err
	}

	_, err = c.etcd.Set(key, backend, 0)
	if err != nil {
		return err
	}

	return err
}

func (c *Client) RegisterFrontend(location *Location) error {
	key := fmt.Sprintf(frontendKey, c.Key, location.Host, location.ID)
	frontend, err := location.Spec()
	if err != nil {
		return err
	}

	_, err = c.etcd.Set(key, frontend, 0)
	if err != nil {
		return err
	}

	return nil
}

func (c *Client) RegisterMiddleware(location *Location) error {
	for i, m := range location.Middlewares {
		m.Priority = i

		key := fmt.Sprintf(middlewareKey, c.Key, location.Host, location.ID, m.ID)
		middleware, err := json.Marshal(m)
		if err != nil {
			return err
		}

		_, err = c.etcd.Set(key, string(middleware), 0)
		if err != nil {
			return err
		}
	}

	return nil
}
<|endoftext|>


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

/*
Package vulncheck detects uses of known vulnerabilities
in Go programs.

vulncheck identifies vulnerability uses in Go programs at the level of call
graph, package import graph, and module requires graph. For instance, vulncheck
identifies which vulnerable functions and methods are transitively called from
the program entry points. vulncheck also detects transitively imported packages
and required modules that contain known vulnerable functions and methods.

A broader overview of vulncheck can be found at
https://go.dev/security/vuln/vulncheck.

# Usage

The two main APIs of vulncheck, Source and Binary, allow vulnerability
detection in Go source code and binaries, respectively.

Source accepts a list of [Package] objects, which are a trimmed version of
[golang.org/x/tools/go/packages.Package] objects to reduce memory consumption.
Binary accepts a path to a Go binary file that must have been compiled with Go
1.18 or greater. Earlier versions omit the list of modules used by the binary,
which vulncheck needs to find vulnerabilities.

Both Source and Binary require information about known vulnerabilities in the
form of a vulnerability database, specifically a
[golang.org/x/vuln/client.Client]. The vulnerabilities are modeled using the
[golang.org/x/vuln/osv] format.

# Results

The results of vulncheck are slices of the call graph, package imports graph,
and module requires graph leading to the use of an identified vulnerability.
Parts of these graphs not related to any vulnerabilities are omitted.

# Vulnerability Witnesses

[CallStacks] and [ImportChains] APIs search the returned slices for
user-friendly representative call stacks and import chains.  Clients of
vulncheck can use these stacks and chains as a witness of a vulnerability use
during, for instance, security review.

# Limitations

Please see the [documented limitations].

[documented limitations]: https://go.dev/security/vulncheck#limitations.
*/
package vulncheck
<commit_msg>vulncheck: update docs<commit_after>// Copyright 2022 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/*
Package vulncheck detects uses of known vulnerabilities
in Go programs.

Vulncheck identifies vulnerability uses in Go programs
at the level of call graph, package import graph, and module
requires graph. For instance, vulncheck identifies which
vulnerable functions and methods are transitively called
from the program entry points. vulncheck also detects
transitively imported packages and required modules that
contain known vulnerable functions and methods.

We recommend using the command line tool [govulncheck] to
detect vulnerabilities in your code.

# Usage

The two main APIs of vulncheck, [Source] and [Binary], allow vulnerability
detection in Go source code and binaries, respectively.

[Source] accepts a list of [Package] objects, which
are a trimmed version of [golang.org/x/tools/go/packages.Package] objects to reduce
memory consumption. [Binary] accepts a path to a Go binary file
that must have been compiled with Go 1.18 or greater. Govulncheck currently
only includes a parser for binaries compiled with Go 1.18 and later.

Both [Source] and [Binary] require information about known
vulnerabilities in the form of a vulnerability database,
specifically a [golang.org/x/vuln/client.Client].
The vulnerabilities
are modeled using the [golang.org/x/vuln/osv] format.

# Results

The results of vulncheck are slices of the call graph, package
imports graph, and module requires graph leading to the use
of an identified vulnerability. The parts of these graphs not
related to any vulnerabilities are omitted.

# Vulnerability Witnesses

[CallStacks] and [ImportChains] APIs search the returned slices
for user-friendly representative call stacks and import chains.
Clients of vulncheck can use these stacks and chains as a
witness of a vulnerability use during, for instance, security
review.

# Limitations

There are some limitations with vulncheck. Please see the
[documented limitations] for more information.

[govulncheck]: https://pkg.go.dev/golang.org/x/vuln/cmd/govulncheck
[documented limitations]: https://go.dev/security/vulncheck#limitations.
*/
package vulncheck
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"strings"

	kingpin "gopkg.in/alecthomas/kingpin.v2"

	"github.com/go-kit/kit/log/level"
	"github.com/prometheus/common/promlog"
	"github.com/prometheus/common/promlog/flag"

	"github.com/robustperception/pushprox/util"
)

var (
	listenAddress = kingpin.Flag("web.listen-address", "Address to listen on for proxy and client requests.").Default(":8080").String()
)

func copyHTTPResponse(resp *http.Response, w http.ResponseWriter) {
	for k, v := range resp.Header {
		w.Header()[k] = v
	}
	w.WriteHeader(resp.StatusCode)
	io.Copy(w, resp.Body)
}

type targetGroup struct {
	Targets []string          `json:"targets"`
	Labels  map[string]string `json:"labels"`
}

func main() {
	allowedLevel := promlog.AllowedLevel{}
	flag.AddFlags(kingpin.CommandLine, &allowedLevel)
	kingpin.HelpFlag.Short('h')
	kingpin.Parse()
	logger := promlog.New(allowedLevel)
	coordinator := NewCoordinator(logger)

	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		// Proxy request
		if r.URL.Host != "" {
			ctx, _ := context.WithTimeout(r.Context(), util.GetScrapeTimeout(r.Header))
			request := r.WithContext(ctx)
			request.RequestURI = ""

			resp, err := coordinator.DoScrape(ctx, request)
			if err != nil {
				level.Error(logger).Log("msg", "Error scraping:", "err", err, "url", request.URL.String())
				http.Error(w, fmt.Sprintf("Error scraping %q: %s", request.URL.String(), err.Error()), 500)
				return
			}
			defer resp.Body.Close()
			copyHTTPResponse(resp, w)
			return
		}

		// Client registering and asking for scrapes.
		if r.URL.Path == "/poll" {
			fqdn, _ := ioutil.ReadAll(r.Body)
			request, err := coordinator.WaitForScrapeInstruction(strings.TrimSpace(string(fqdn)))
			if err != nil {
				level.Info(logger).Log("msg", "Error WaitForScrapeInstruction:", "err", err)
				http.Error(w, fmt.Sprintf("Error WaitForScrapeInstruction: %s", err.Error()), 408)
				return
			}
			request.WriteProxy(w) // Send full request as the body of the response.
			level.Info(logger).Log("msg", "Responded to /poll", "url", request.URL.String(), "scrape_id", request.Header.Get("Id"))
			return
		}

		// Scrape response from client.
		if r.URL.Path == "/push" {
			buf := &bytes.Buffer{}
			io.Copy(buf, r.Body)
			scrapeResult, _ := http.ReadResponse(bufio.NewReader(buf), nil)
			level.Info(logger).Log("msg", "Got /push", "scrape_id", scrapeResult.Header.Get("Id"))
			err := coordinator.ScrapeResult(scrapeResult)
			if err != nil {
				level.Error(logger).Log("msg", "Error pushing:", "err", err, "scrape_id", scrapeResult.Header.Get("Id"))
				http.Error(w, fmt.Sprintf("Error pushing: %s", err.Error()), 500)
			}
			return
		}

		if r.URL.Path == "/clients" {
			known := coordinator.KnownClients()
			targets := make([]*targetGroup, 0, len(known))
			for _, k := range known {
				targets = append(targets, &targetGroup{Targets: []string{k}})
			}
			json.NewEncoder(w).Encode(targets)
			level.Info(logger).Log("msg", "Responded to /clients", "client_count", len(known))
			return
		}

		http.Error(w, "404: Unknown path", 404)
	})

	level.Info(logger).Log("msg", "Listening", "address", *listenAddress)
	if err := http.ListenAndServe(*listenAddress, nil); err != nil {
		level.Error(logger).Log("msg", "Listening failed", "err", err)
		os.Exit(1)
	}
}
<commit_msg>fix: Do not swallow http.ReadResponse errors (#35)<commit_after>package main

import (
	"bufio"
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"strings"

	kingpin "gopkg.in/alecthomas/kingpin.v2"

	"github.com/go-kit/kit/log/level"
	"github.com/prometheus/common/promlog"
	"github.com/prometheus/common/promlog/flag"

	"github.com/robustperception/pushprox/util"
)

var (
	listenAddress = kingpin.Flag("web.listen-address", "Address to listen on for proxy and client requests.").Default(":8080").String()
)

func copyHTTPResponse(resp *http.Response, w http.ResponseWriter) {
	for k, v := range resp.Header {
		w.Header()[k] = v
	}
	w.WriteHeader(resp.StatusCode)
	io.Copy(w, resp.Body)
}

type targetGroup struct {
	Targets []string          `json:"targets"`
	Labels  map[string]string `json:"labels"`
}

func main() {
	allowedLevel := promlog.AllowedLevel{}
	flag.AddFlags(kingpin.CommandLine, &allowedLevel)
	kingpin.HelpFlag.Short('h')
	kingpin.Parse()
	logger := promlog.New(allowedLevel)
	coordinator := NewCoordinator(logger)

	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		// Proxy request
		if r.URL.Host != "" {
			ctx, _ := context.WithTimeout(r.Context(), util.GetScrapeTimeout(r.Header))
			request := r.WithContext(ctx)
			request.RequestURI = ""

			resp, err := coordinator.DoScrape(ctx, request)
			if err != nil {
				level.Error(logger).Log("msg", "Error scraping:", "err", err, "url", request.URL.String())
				http.Error(w, fmt.Sprintf("Error scraping %q: %s", request.URL.String(), err.Error()), 500)
				return
			}
			defer resp.Body.Close()
			copyHTTPResponse(resp, w)
			return
		}

		// Client registering and asking for scrapes.
		if r.URL.Path == "/poll" {
			fqdn, _ := ioutil.ReadAll(r.Body)
			request, err := coordinator.WaitForScrapeInstruction(strings.TrimSpace(string(fqdn)))
			if err != nil {
				level.Info(logger).Log("msg", "Error WaitForScrapeInstruction:", "err", err)
				http.Error(w, fmt.Sprintf("Error WaitForScrapeInstruction: %s", err.Error()), 408)
				return
			}
			request.WriteProxy(w) // Send full request as the body of the response.
			level.Info(logger).Log("msg", "Responded to /poll", "url", request.URL.String(), "scrape_id", request.Header.Get("Id"))
			return
		}

		// Scrape response from client.
		if r.URL.Path == "/push" {
			buf := &bytes.Buffer{}
			io.Copy(buf, r.Body)
			scrapeResult, err := http.ReadResponse(bufio.NewReader(buf), nil)
			if err != nil {
				level.Error(logger).Log("msg", "Error reading pushed response:", "err", err)
				http.Error(w, fmt.Sprintf("Error pushing: %s", err.Error()), 500)
				return
			}
			level.Info(logger).Log("msg", "Got /push", "scrape_id", scrapeResult.Header.Get("Id"))
			err = coordinator.ScrapeResult(scrapeResult)
			if err != nil {
				level.Error(logger).Log("msg", "Error pushing:", "err", err, "scrape_id", scrapeResult.Header.Get("Id"))
				http.Error(w, fmt.Sprintf("Error pushing: %s", err.Error()), 500)
			}
			return
		}

		if r.URL.Path == "/clients" {
			known := coordinator.KnownClients()
			targets := make([]*targetGroup, 0, len(known))
			for _, k := range known {
				targets = append(targets, &targetGroup{Targets: []string{k}})
			}
			json.NewEncoder(w).Encode(targets)
			level.Info(logger).Log("msg", "Responded to /clients", "client_count", len(known))
			return
		}

		http.Error(w, "404: Unknown path", 404)
	})

	level.Info(logger).Log("msg", "Listening", "address", *listenAddress)
	if err := http.ListenAndServe(*listenAddress, nil); err != nil {
		level.Error(logger).Log("msg", "Listening failed", "err", err)
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package proxy

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"io"
	"net"
	"os"
	"strings"
	"time"

	"github.com/DimShadoWWW/power-pg/common"
	"github.com/op/go-logging"
)

var (
	connid = uint64(0)
)

// Pkg PostgreSQL package structure
type Pkg struct {
	Type    byte
	Content []byte
	Time    time.Time
}

// Start function
func Start(localHost, remoteHost *string, remotePort *string, msgBytes chan []byte, msgCh chan Pkg, recreate bool, log *logging.Logger) {
	fmt.Printf("Proxying from %v to %v\n", localHost, remoteHost)

	localAddr, remoteAddr := getResolvedAddresses(localHost, remoteHost, remotePort)
	listener := getListener(localAddr)

	for {
		conn, err := listener.AcceptTCP()
		if err != nil {
			fmt.Printf("Failed to accept connection '%s'\n", err)
			continue
		}
		connid++

		p := &proxy{
			lconn:  *conn,
			laddr:  localAddr,
			raddr:  remoteAddr,
			erred:  false,
			errsig: make(chan bool),
			prefix: fmt.Sprintf("Connection #%03d ", connid),
			log:    log,
		}
		go p.start(msgBytes, msgCh, recreate)
	}
}

func getResolvedAddresses(localHost, remoteHost, remotePort *string) (*net.TCPAddr, *net.TCPAddr) {
	laddr, err := net.ResolveTCPAddr("tcp", *localHost)
	check(err)
	raddr, err := net.ResolveTCPAddr("tcp", fmt.Sprintf("%s:%s", *remoteHost, *remotePort))
	check(err)
	return laddr, raddr
}

func getListener(addr *net.TCPAddr) *net.TCPListener {
	listener, err := net.ListenTCP("tcp", addr)
	check(err)
	return listener
}

type proxy struct {
	sentBytes     uint64
	receivedBytes uint64
	laddr, raddr  *net.TCPAddr
	lconn, rconn  net.TCPConn
	erred         bool
	errsig        chan bool
	prefix        string
	result        *[]string
	log           *logging.Logger
}

func (p *proxy) err(s string, err error) {
	if p.erred {
		return
	}
	if err != io.EOF {
		warn(p.prefix+s, err)
	}
	p.errsig <- true
	p.erred = true
}

func (p *proxy) start(msgBytes chan []byte, msgCh chan Pkg, recreate bool) {
	// defer p.lconn.conn.Close()
	//connect to remote
	rconn, err := net.DialTCP("tcp", nil, p.raddr)
	if err != nil {
		p.err("Remote connection failed: %s", err)
		return
	}
	p.rconn = *rconn
	// p.rconn.alive = true
	// defer p.rconn.conn.Close()
	//bidirectional copy
	go p.pipe(p.lconn, p.rconn, msgBytes, msgCh, recreate, p.log)
	go p.pipe(p.rconn, p.lconn, nil, nil, recreate, p.log)
	//wait for close...
	<-p.errsig
}

func (p *proxy) pipe(src, dst net.TCPConn, msgBytes chan []byte, msgCh chan Pkg, recreate bool, log *logging.Logger) {
	//data direction
	islocal := src == p.lconn
	//directional copy (64k buffer)
	buff := make(ReadBuf, 0xffff)

	// spaces := regexp.MustCompile("[\n\t ]+")
	if islocal {
		for {
			remainingBytes := 0
			var r ReadBuf

			// fmt.Println("1111")
			n, err := src.Read(buff)
			if err != nil {
				p.err("Read failed '%s'\n", err)
				return
			}

			// if msgBytes != nil {
			// log.Debug("Readed bytes: %d\n", n)
			// }
			b := buff[:n]
			// log.Info("Readed: %v\n", b)
			msgBytes <- b
			//write out result
			if !recreate {
				n, err = dst.Write(b)
				if err != nil {
					p.err("Write failed '%s'\n", err)
					return
				}
			}
			r = buff[:n]
			// log.Debug("PostgreSQL full message: %s\n", string(r))
			// // log.Debug("Remaining bytes: %d\n", remainingBytes)
			// log.Debug("len(r) : %v\n", len(r))
			// fmt.Println("3")
			if len(r) > 4 {
				// fmt.Println("4")
				// log.Debug("2 Remaining bytes: %d\n", remainingBytes)

				var msg []byte
				// log.Debug("1 n: %d\n", n)
				t := r.Byte()
				// fmt.Println("t: ", string(t))
				switch t {
				// case 'Q', 'B', 'C', 'd', 'c', 'f', 'D', 'E', 'H', 'F', 'P', 'p', 'S', 'X':
				case 'B', 'P':
					log.Debug("PostgreSQL pkg type: %s\n", string(t))
					remainingBytes = r.Int32() - 4
					r = r[:remainingBytes]
					if remainingBytes < 4 {
						fmt.Println("ERROR: remainingBytes can't be less than 4 bytes if int32")
					} else {
						if remainingBytes > 0 {
							msg = append(msg, r.Next(remainingBytes)[:]...)
							msgCh <- Pkg{
								Type:    t,
								Content: msg,
								Time:    time.Now(),
							}
						}
					}
				case 'Q':
					if !bytes.Contains(r, []byte("DEALLOCATE")) {
						log.Debug("PostgreSQL pkg type: %s\n", string(t))
						remainingBytes = r.Int32() - 4
						r = r[:remainingBytes]
						msgCh <- Pkg{
							Type:    t,
							Content: r,
							Time:    time.Now(),
						}
					}
				}
			}
			// fmt.Println("8")
		}
	} else {
		for {
			n, err := src.Read(buff)
			if err != nil {
				p.err("Read failed '%s'\n", err)
				return
			}
			b := buff[:n]
			//write out result
			n, err = dst.Write(b)
			if err != nil {
				p.err("Write failed '%s'\n", err)
				return
			}
			if err != nil {
				p.err("Write failed '%s'\n", err)
				return
			}
		}
	}
}

func getModifiedBuffer(buffer []byte, powerCallback common.Callback) []byte {
	if powerCallback == nil || len(buffer) < 1 || string(buffer[0]) != "Q" || string(buffer[5:11]) != "power:" {
		return buffer
	}
	query := powerCallback(string(buffer[5:]))
	return makeMessage(query)
}

func makeMessage(query string) []byte {
	queryArray := make([]byte, 0, 6+len(query))
	queryArray = append(queryArray, 'Q', 0, 0, 0, 0)
	queryArray = append(queryArray, query...)
	queryArray = append(queryArray, 0)
	binary.BigEndian.PutUint32(queryArray[1:], uint32(len(queryArray)-1))
	return queryArray

}

func check(err error) {
	if err != nil {
		warn(err.Error())
		os.Exit(1)
	}
}

func warn(f string, args ...interface{}) {
	fmt.Printf(f+"\n", args...)
}

func stripchars(str, chr string) string {
	return strings.Map(func(r rune) rune {
		if strings.IndexRune(chr, r) < 0 {
			return r
		}
		return -1
	}, str)
}
<commit_msg>Update<commit_after>package proxy

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"io"
	"net"
	"os"
	"strings"
	"time"

	"github.com/DimShadoWWW/power-pg/common"
	"github.com/op/go-logging"
)

var (
	connid = uint64(0)
)

// Pkg PostgreSQL package structure
type Pkg struct {
	Type    byte
	Content []byte
	Time    time.Time
}

// Start function
func Start(localHost, remoteHost *string, remotePort *string, msgBytes chan []byte, msgCh chan Pkg, recreate bool, log *logging.Logger) {
	fmt.Printf("Proxying from %v to %v\n", localHost, remoteHost)

	localAddr, remoteAddr := getResolvedAddresses(localHost, remoteHost, remotePort)
	listener := getListener(localAddr)

	for {
		conn, err := listener.AcceptTCP()
		if err != nil {
			fmt.Printf("Failed to accept connection '%s'\n", err)
			continue
		}
		connid++

		p := &proxy{
			lconn:  *conn,
			laddr:  localAddr,
			raddr:  remoteAddr,
			erred:  false,
			errsig: make(chan bool),
			prefix: fmt.Sprintf("Connection #%03d ", connid),
			log:    log,
		}
		go p.start(msgBytes, msgCh, recreate)
	}
}

func getResolvedAddresses(localHost, remoteHost, remotePort *string) (*net.TCPAddr, *net.TCPAddr) {
	laddr, err := net.ResolveTCPAddr("tcp", *localHost)
	check(err)
	raddr, err := net.ResolveTCPAddr("tcp", fmt.Sprintf("%s:%s", *remoteHost, *remotePort))
	check(err)
	return laddr, raddr
}

func getListener(addr *net.TCPAddr) *net.TCPListener {
	listener, err := net.ListenTCP("tcp", addr)
	check(err)
	return listener
}

type proxy struct {
	sentBytes     uint64
	receivedBytes uint64
	laddr, raddr  *net.TCPAddr
	lconn, rconn  net.TCPConn
	erred         bool
	errsig        chan bool
	prefix        string
	result        *[]string
	log           *logging.Logger
}

func (p *proxy) err(s string, err error) {
	if p.erred {
		return
	}
	if err != io.EOF {
		warn(p.prefix+s, err)
	}
	p.errsig <- true
	p.erred = true
}

func (p *proxy) start(msgBytes chan []byte, msgCh chan Pkg, recreate bool) {
	// defer p.lconn.conn.Close()
	//connect to remote
	rconn, err := net.DialTCP("tcp", nil, p.raddr)
	if err != nil {
		p.err("Remote connection failed: %s", err)
		return
	}
	p.rconn = *rconn
	// p.rconn.alive = true
	// defer p.rconn.conn.Close()
	//bidirectional copy
	go p.pipe(p.lconn, p.rconn, msgBytes, msgCh, recreate, p.log)
	go p.pipe(p.rconn, p.lconn, nil, nil, recreate, p.log)
	//wait for close...
	<-p.errsig
}

func (p *proxy) pipe(src, dst net.TCPConn, msgBytes chan []byte, msgCh chan Pkg, recreate bool, log *logging.Logger) {
	//data direction
	islocal := src == p.lconn
	//directional copy (64k buffer)
	buff := make(ReadBuf, 0xffff)

	// spaces := regexp.MustCompile("[\n\t ]+")
	if islocal {
		for {
			remainingBytes := 0
			var r ReadBuf
			now := time.Now()

			// fmt.Println("1111")
			n, err := src.Read(buff)
			if err != nil {
				p.err("Read failed '%s'\n", err)
				return
			}

			// if msgBytes != nil {
			// log.Debug("Readed bytes: %d\n", n)
			// }
			b := buff[:n]
			// log.Info("Readed: %v\n", b)
			msgBytes <- b
			//write out result
			if !recreate {
				n, err = dst.Write(b)
				if err != nil {
					p.err("Write failed '%s'\n", err)
					return
				}
			}
			r = buff[:n]
			// log.Debug("PostgreSQL full message: %s\n", string(r))
			// // log.Debug("Remaining bytes: %d\n", remainingBytes)
			// log.Debug("len(r) : %v\n", len(r))
			// fmt.Println("3")
			if len(r) > 4 {
				// fmt.Println("4")
				// log.Debug("2 Remaining bytes: %d\n", remainingBytes)

				var msg []byte
				// log.Debug("1 n: %d\n", n)
				t := r.Byte()
				// fmt.Println("t: ", string(t))
				switch t {
				// case 'Q', 'B', 'C', 'd', 'c', 'f', 'D', 'E', 'H', 'F', 'P', 'p', 'S', 'X':
				case 'B', 'P':
					log.Debug("PostgreSQL pkg type: %s\n", string(t))
					remainingBytes = r.Int32() - 4
					r = r[:remainingBytes]
					if remainingBytes < 4 {
						fmt.Println("ERROR: remainingBytes can't be less than 4 bytes if int32")
					} else {
						if remainingBytes > 0 {
							msg = append(msg, r.Next(remainingBytes)[:]...)
							msgCh <- Pkg{
								Type:    t,
								Content: msg,
								Time:    now,
							}
						}
					}
				case 'Q':
					if !bytes.Contains(r, []byte("DEALLOCATE")) {
						log.Debug("PostgreSQL pkg type: %s\n", string(t))
						remainingBytes = r.Int32() - 4
						r = r[:remainingBytes]
						msgCh <- Pkg{
							Type:    t,
							Content: r,
							Time:    now,
						}
					}
				}
			}

			log.Debug("Going to next query\n")
			// fmt.Println("8")
		}
	} else {
		for {
			n, err := src.Read(buff)
			if err != nil {
				p.err("Read failed '%s'\n", err)
				return
			}
			b := buff[:n]
			//write out result
			n, err = dst.Write(b)
			if err != nil {
				p.err("Write failed '%s'\n", err)
				return
			}
			if err != nil {
				p.err("Write failed '%s'\n", err)
				return
			}
		}
	}
}

func getModifiedBuffer(buffer []byte, powerCallback common.Callback) []byte {
	if powerCallback == nil || len(buffer) < 1 || string(buffer[0]) != "Q" || string(buffer[5:11]) != "power:" {
		return buffer
	}
	query := powerCallback(string(buffer[5:]))
	return makeMessage(query)
}

func makeMessage(query string) []byte {
	queryArray := make([]byte, 0, 6+len(query))
	queryArray = append(queryArray, 'Q', 0, 0, 0, 0)
	queryArray = append(queryArray, query...)
	queryArray = append(queryArray, 0)
	binary.BigEndian.PutUint32(queryArray[1:], uint32(len(queryArray)-1))
	return queryArray

}

func check(err error) {
	if err != nil {
		warn(err.Error())
		os.Exit(1)
	}
}

func warn(f string, args ...interface{}) {
	fmt.Printf(f+"\n", args...)
}

func stripchars(str, chr string) string {
	return strings.Map(func(r rune) rune {
		if strings.IndexRune(chr, r) < 0 {
			return r
		}
		return -1
	}, str)
}
<|endoftext|>


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

// Package proxy provides the image proxy.
package proxy

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"reflect"

	"github.com/golang/glog"
	"github.com/gregjones/httpcache"
)

// Proxy serves image requests.
type Proxy struct {
	Client *http.Client // client used to fetch remote URLs
	Cache  Cache

	// Whitelist specifies a list of remote hosts that images can be proxied from.  An empty list means all hosts are allowed.
	Whitelist []string

	MaxWidth  int
	MaxHeight int
}

// NewProxy constructs a new proxy.  The provided http Client will be used to
// fetch remote URLs.  If nil is provided, http.DefaultClient will be used.
func NewProxy(transport http.RoundTripper, cache Cache) *Proxy {
	if transport == nil {
		transport = http.DefaultTransport
	}
	if cache == nil {
		cache = NopCache
	}

	client := new(http.Client)
	client.Transport = &httpcache.Transport{
		Transport:           &TransformingTransport{transport, client},
		Cache:               cache,
		MarkCachedResponses: true,
	}

	return &Proxy{
		Client: client,
		Cache:  cache,
	}
}

// ServeHTTP handles image requests.
func (p *Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	req, err := NewRequest(r)
	if err != nil {
		glog.Errorf("invalid request URL: %v", err)
		http.Error(w, fmt.Sprintf("invalid request URL: %v", err), http.StatusBadRequest)
		return
	}

	if p.MaxWidth > 0 && int(req.Options.Width) > p.MaxWidth {
		req.Options.Width = float64(p.MaxWidth)
	}
	if p.MaxHeight > 0 && int(req.Options.Height) > p.MaxHeight {
		req.Options.Height = float64(p.MaxHeight)
	}

	if !p.allowed(req.URL) {
		glog.Errorf("remote URL is not for an allowed host: %v", req.URL.Host)
		http.Error(w, fmt.Sprintf("remote URL is not for an allowed host: %v", req.URL.Host), http.StatusBadRequest)
		return
	}

	u := req.URL.String()
	if req.Options != nil && !reflect.DeepEqual(req.Options, emptyOptions) {
		u += "#" + req.Options.String()
	}
	resp, err := p.Client.Get(u)
	if err != nil {
		glog.Errorf("error fetching remote image: %v", err)
		http.Error(w, fmt.Sprintf("Error fetching remote image: %v", err), http.StatusInternalServerError)
		return
	}

	if resp.StatusCode != http.StatusOK {
		http.Error(w, fmt.Sprintf("Remote URL %q returned status: %v", req.URL, resp.Status), http.StatusInternalServerError)
		return
	}

	w.Header().Add("Content-Length", resp.Header.Get("Content-Length"))
	w.Header().Add("Expires", resp.Header.Get("Expires"))

	defer resp.Body.Close()
	io.Copy(w, resp.Body)
}

// allowed returns whether the specified URL is on the whitelist of remote hosts.
func (p *Proxy) allowed(u *url.URL) bool {
	if len(p.Whitelist) == 0 {
		return true
	}

	for _, host := range p.Whitelist {
		if u.Host == host {
			return true
		}
	}

	return false
}

// TransformingTransport is an implementation of http.RoundTripper that
// optionally transforms images using the options specified in the request URL
// fragment.
type TransformingTransport struct {
	// Transport is used to satisfy non-transform requests (those that do not include a URL fragment)
	Transport http.RoundTripper

	// Client is used to fetch images to be resized.
	Client *http.Client
}

// RoundTrip implements http.RoundTripper.
func (t *TransformingTransport) RoundTrip(req *http.Request) (*http.Response, error) {
	if req.URL.Fragment == "" {
		// normal requests pass through
		glog.Infof("fetching remote URL: %v", req.URL)
		return t.Transport.RoundTrip(req)
	}

	u := *req.URL
	u.Fragment = ""
	resp, err := t.Client.Get(u.String())

	defer resp.Body.Close()
	b, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	opt := ParseOptions(req.URL.Fragment)
	img, err := Transform(b, opt)
	if err != nil {
		img = b
	}

	// replay response with transformed image and updated content length
	buf := new(bytes.Buffer)
	fmt.Fprintf(buf, "%s %s\n", resp.Proto, resp.Status)
	resp.Header.WriteSubset(buf, map[string]bool{"Content-Length": true})
	fmt.Fprintf(buf, "Content-Length: %d\n\n", len(img))
	buf.Write(img)

	return http.ReadResponse(bufio.NewReader(buf), req)
}
<commit_msg>etag and last-modified support on incoming requests<commit_after>// Copyright 2013 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package proxy provides the image proxy.
package proxy

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"reflect"
	"time"

	"github.com/golang/glog"
	"github.com/gregjones/httpcache"
)

// Proxy serves image requests.
type Proxy struct {
	Client *http.Client // client used to fetch remote URLs
	Cache  Cache

	// Whitelist specifies a list of remote hosts that images can be proxied from.  An empty list means all hosts are allowed.
	Whitelist []string

	MaxWidth  int
	MaxHeight int
}

// NewProxy constructs a new proxy.  The provided http Client will be used to
// fetch remote URLs.  If nil is provided, http.DefaultClient will be used.
func NewProxy(transport http.RoundTripper, cache Cache) *Proxy {
	if transport == nil {
		transport = http.DefaultTransport
	}
	if cache == nil {
		cache = NopCache
	}

	client := new(http.Client)
	client.Transport = &httpcache.Transport{
		Transport:           &TransformingTransport{transport, client},
		Cache:               cache,
		MarkCachedResponses: true,
	}

	return &Proxy{
		Client: client,
		Cache:  cache,
	}
}

// ServeHTTP handles image requests.
func (p *Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	req, err := NewRequest(r)
	if err != nil {
		glog.Errorf("invalid request URL: %v", err)
		http.Error(w, fmt.Sprintf("invalid request URL: %v", err), http.StatusBadRequest)
		return
	}

	if p.MaxWidth > 0 && int(req.Options.Width) > p.MaxWidth {
		req.Options.Width = float64(p.MaxWidth)
	}
	if p.MaxHeight > 0 && int(req.Options.Height) > p.MaxHeight {
		req.Options.Height = float64(p.MaxHeight)
	}

	if !p.allowed(req.URL) {
		glog.Errorf("remote URL is not for an allowed host: %v", req.URL.Host)
		http.Error(w, fmt.Sprintf("remote URL is not for an allowed host: %v", req.URL.Host), http.StatusBadRequest)
		return
	}

	u := req.URL.String()
	if req.Options != nil && !reflect.DeepEqual(req.Options, emptyOptions) {
		u += "#" + req.Options.String()
	}
	resp, err := p.Client.Get(u)
	if err != nil {
		glog.Errorf("error fetching remote image: %v", err)
		http.Error(w, fmt.Sprintf("Error fetching remote image: %v", err), http.StatusInternalServerError)
		return
	}

	if resp.StatusCode != http.StatusOK {
		http.Error(w, fmt.Sprintf("Remote URL %q returned status: %v", req.URL, resp.Status), http.StatusInternalServerError)
		return
	}

	w.Header().Add("Last-Modified", resp.Header.Get("Last-Modified"))
	w.Header().Add("Expires", resp.Header.Get("Expires"))
	w.Header().Add("Etag", resp.Header.Get("Etag"))

	if is304 := check304(w, r, resp); is304 {
		w.WriteHeader(http.StatusNotModified)
		return
	}

	w.Header().Add("Content-Length", resp.Header.Get("Content-Length"))
	defer resp.Body.Close()
	io.Copy(w, resp.Body)
}

// allowed returns whether the specified URL is on the whitelist of remote hosts.
func (p *Proxy) allowed(u *url.URL) bool {
	if len(p.Whitelist) == 0 {
		return true
	}

	for _, host := range p.Whitelist {
		if u.Host == host {
			return true
		}
	}

	return false
}

func check304(w http.ResponseWriter, req *http.Request, resp *http.Response) bool {
	etag := resp.Header.Get("Etag")
	if etag != "" && etag == req.Header.Get("If-None-Match") {
		return true
	}

	lastModified, err := time.Parse(time.RFC1123, resp.Header.Get("Last-Modified"))
	if err != nil {
		return false
	}
	ifModSince, err := time.Parse(time.RFC1123, req.Header.Get("If-Modified-Since"))
	if err != nil {
		return false
	}
	if lastModified.Before(ifModSince) {
		return true
	}

	return false
}

// TransformingTransport is an implementation of http.RoundTripper that
// optionally transforms images using the options specified in the request URL
// fragment.
type TransformingTransport struct {
	// Transport is used to satisfy non-transform requests (those that do not include a URL fragment)
	Transport http.RoundTripper

	// Client is used to fetch images to be resized.
	Client *http.Client
}

// RoundTrip implements http.RoundTripper.
func (t *TransformingTransport) RoundTrip(req *http.Request) (*http.Response, error) {
	if req.URL.Fragment == "" {
		// normal requests pass through
		glog.Infof("fetching remote URL: %v", req.URL)
		return t.Transport.RoundTrip(req)
	}

	u := *req.URL
	u.Fragment = ""
	resp, err := t.Client.Get(u.String())

	defer resp.Body.Close()
	b, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	opt := ParseOptions(req.URL.Fragment)
	img, err := Transform(b, opt)
	if err != nil {
		img = b
	}

	// replay response with transformed image and updated content length
	buf := new(bytes.Buffer)
	fmt.Fprintf(buf, "%s %s\n", resp.Proto, resp.Status)
	resp.Header.WriteSubset(buf, map[string]bool{"Content-Length": true})
	fmt.Fprintf(buf, "Content-Length: %d\n\n", len(img))
	buf.Write(img)

	return http.ReadResponse(bufio.NewReader(buf), req)
}
<|endoftext|>


<commit_before>package proxy

import (
	"encoding/binary"
	"fmt"
	"io"
	"net"
	"os"

	"github.com/DimShadoWWW/power-pg/common"
)

var (
	connid = uint64(0)
)

// Start function
func Start(localHost, remoteHost *string, powerCallback common.Callback) {
	fmt.Printf("Proxying from %v to %v\n", localHost, remoteHost)

	localAddr, remoteAddr := getResolvedAddresses(localHost, remoteHost)
	listener := getListener(localAddr)

	for {
		conn, err := listener.AcceptTCP()
		if err != nil {
			fmt.Printf("Failed to accept connection '%s'\n", err)
			continue
		}
		connid++

		p := &proxy{
			lconn:  *conn,
			laddr:  localAddr,
			raddr:  remoteAddr,
			erred:  false,
			errsig: make(chan bool),
			prefix: fmt.Sprintf("Connection #%03d ", connid),
		}
		go p.start(powerCallback)
	}
}

func getResolvedAddresses(localHost, remoteHost *string) (*net.TCPAddr, *net.TCPAddr) {
	laddr, err := net.ResolveTCPAddr("tcp", *localHost)
	check(err)
	raddr, err := net.ResolveTCPAddr("tcp", *remoteHost)
	check(err)
	return laddr, raddr
}

func getListener(addr *net.TCPAddr) *net.TCPListener {
	listener, err := net.ListenTCP("tcp", addr)
	check(err)
	return listener
}

type proxy struct {
	sentBytes     uint64
	receivedBytes uint64
	laddr, raddr  *net.TCPAddr
	lconn, rconn  net.TCPConn
	erred         bool
	errsig        chan bool
	prefix        string
}

func (p *proxy) err(s string, err error) {
	if p.erred {
		return
	}
	if err != io.EOF {
		warn(p.prefix+s, err)
	}
	p.errsig <- true
	p.erred = true
}

func (p *proxy) start(powerCallback common.Callback) {
	// defer p.lconn.conn.Close()
	//connect to remote
	rconn, err := net.DialTCP("tcp", nil, p.raddr)
	if err != nil {
		p.err("Remote connection failed: %s", err)
		return
	}
	p.rconn = *rconn
	// p.rconn.alive = true
	// defer p.rconn.conn.Close()
	//bidirectional copy
	go p.pipe(p.lconn, p.rconn, powerCallback)
	go p.pipe(p.rconn, p.lconn, nil)
	//wait for close...
	<-p.errsig
}

func (p *proxy) pipe(src, dst net.TCPConn, powerCallback common.Callback) {
	//data direction
	islocal := src == p.lconn
	//directional copy (64k buffer)
	buff := make(readBuf, 0xffff)
	newPacket := true
	var msg string
	remainingBytes := 0
	if islocal {
		for {
			var r readBuf
			n, err := src.Read(buff)
			if err != nil {
				p.err("Read failed '%s'\n", err)
				return
			}
			fmt.Printf("Readed bytes: %d\n", n)
			b := buff[:n]
			//write out result
			n, err = dst.Write(b)
			if err != nil {
				p.err("Write failed '%s'\n", err)
				return
			}

			r = buff[:n]
			fmt.Printf("%#v\n", buff[:n])
			if remainingBytes > 0 {
				if remainingBytes <= n {
					newPacket = true
					msg = msg + string(r.next(remainingBytes))
					remainingBytes = n - remainingBytes
					fmt.Println(msg)
				} else {
					newPacket = false
					msg = msg + string(r.next(remainingBytes))
					remainingBytes = remainingBytes - n
				}
			}
			fmt.Printf("Remaining bytes: %d\n", remainingBytes)
		NewP:
			if newPacket {
				remainingBytes = 0
				newPacket = false
				msg = ""
				t := r.byte()
				n = n - 1
				fmt.Println(t)
				switch t {
				case query:
					// c.rxReadyForQuery(r)
					remainingBytes = r.int32()
					remainingBytes = remainingBytes - 4
					if remainingBytes > 0 {
						if remainingBytes <= n {
							newPacket = true
							msg = msg + string(r.next(remainingBytes))
							remainingBytes = n - remainingBytes
							fmt.Println(msg)
							goto NewP
						} else {
							newPacket = false
							msg = msg + string(r.next(remainingBytes))
							remainingBytes = remainingBytes - n
						}
						fmt.Printf("Remaining bytes: %d\n", remainingBytes)
					}
				// case rowDescription:
				// case dataRow:
				// case bindComplete:
				// case commandComplete:
				// 	commandTag = CommandTag(r.readCString())
				default:
					// if e := c.processContextFreeMsg(t, r); e != nil && softErr == nil {
					// 	softErr = e
					// }
				}
			}
			r = append(r, buff[:]...)

			// fmt.Println("a")
			// c := src
			// c.reader = bufio.NewReader(src.conn)
			// c.mr.reader = c.reader
			//
			// var t byte
			// var r *msgReader
			// fmt.Println("b")
			// t, r, err := c.rxMsg()
			// fmt.Println("c")
			// if err != nil {
			// 	fmt.Println(err)
			// 	return
			// }
			// fmt.Println("d")
			//
			// fmt.Printf("t: %#v\n", t)

			// n, err := src.Read(buff)
			// if err != nil {
			// 	p.err("Read failed '%s'\n", err)
			// 	return
			// }
			// b := buff[:n]
			// //show output
			//
			//
			// b = getModifiedBuffer(b, powerCallback)
			// n, err = dst.Write(b)
			// //
			// //write out result
			// n, err = dst.Write(b)
			// if err != nil {
			// 	p.err("Write failed '%s'\n", err)
			// 	return
			// }
		}
	} else {
		for {
			n, err := src.Read(buff)
			if err != nil {
				p.err("Read failed '%s'\n", err)
				return
			}
			b := buff[:n]
			//write out result
			n, err = dst.Write(b)
			if err != nil {
				p.err("Write failed '%s'\n", err)
				return
			}
			if err != nil {
				p.err("Write failed '%s'\n", err)
				return
			}
		}
	}
}

func getModifiedBuffer(buffer []byte, powerCallback common.Callback) []byte {
	if powerCallback == nil || len(buffer) < 1 || string(buffer[0]) != "Q" || string(buffer[5:11]) != "power:" {
		return buffer
	}
	query := powerCallback(string(buffer[5:]))
	return makeMessage(query)
}

func makeMessage(query string) []byte {
	queryArray := make([]byte, 0, 6+len(query))
	queryArray = append(queryArray, 'Q', 0, 0, 0, 0)
	queryArray = append(queryArray, query...)
	queryArray = append(queryArray, 0)
	binary.BigEndian.PutUint32(queryArray[1:], uint32(len(queryArray)-1))
	return queryArray

}

func check(err error) {
	if err != nil {
		warn(err.Error())
		os.Exit(1)
	}
}

func warn(f string, args ...interface{}) {
	fmt.Printf(f+"\n", args...)
}
<commit_msg>Update<commit_after>package proxy

import (
	"encoding/binary"
	"fmt"
	"io"
	"net"
	"os"

	"github.com/DimShadoWWW/power-pg/common"
)

var (
	connid = uint64(0)
)

// Start function
func Start(localHost, remoteHost *string, powerCallback common.Callback) {
	fmt.Printf("Proxying from %v to %v\n", localHost, remoteHost)

	localAddr, remoteAddr := getResolvedAddresses(localHost, remoteHost)
	listener := getListener(localAddr)

	for {
		conn, err := listener.AcceptTCP()
		if err != nil {
			fmt.Printf("Failed to accept connection '%s'\n", err)
			continue
		}
		connid++

		p := &proxy{
			lconn:  *conn,
			laddr:  localAddr,
			raddr:  remoteAddr,
			erred:  false,
			errsig: make(chan bool),
			prefix: fmt.Sprintf("Connection #%03d ", connid),
		}
		go p.start(powerCallback)
	}
}

func getResolvedAddresses(localHost, remoteHost *string) (*net.TCPAddr, *net.TCPAddr) {
	laddr, err := net.ResolveTCPAddr("tcp", *localHost)
	check(err)
	raddr, err := net.ResolveTCPAddr("tcp", *remoteHost)
	check(err)
	return laddr, raddr
}

func getListener(addr *net.TCPAddr) *net.TCPListener {
	listener, err := net.ListenTCP("tcp", addr)
	check(err)
	return listener
}

type proxy struct {
	sentBytes     uint64
	receivedBytes uint64
	laddr, raddr  *net.TCPAddr
	lconn, rconn  net.TCPConn
	erred         bool
	errsig        chan bool
	prefix        string
}

func (p *proxy) err(s string, err error) {
	if p.erred {
		return
	}
	if err != io.EOF {
		warn(p.prefix+s, err)
	}
	p.errsig <- true
	p.erred = true
}

func (p *proxy) start(powerCallback common.Callback) {
	// defer p.lconn.conn.Close()
	//connect to remote
	rconn, err := net.DialTCP("tcp", nil, p.raddr)
	if err != nil {
		p.err("Remote connection failed: %s", err)
		return
	}
	p.rconn = *rconn
	// p.rconn.alive = true
	// defer p.rconn.conn.Close()
	//bidirectional copy
	go p.pipe(p.lconn, p.rconn, powerCallback)
	go p.pipe(p.rconn, p.lconn, nil)
	//wait for close...
	<-p.errsig
}

func (p *proxy) pipe(src, dst net.TCPConn, powerCallback common.Callback) {
	//data direction
	islocal := src == p.lconn
	//directional copy (64k buffer)
	buff := make(readBuf, 0xffff)
	newPacket := true
	var msg string
	remainingBytes := 0
	if islocal {
		for {
			var r readBuf
			n, err := src.Read(buff)
			if err != nil {
				p.err("Read failed '%s'\n", err)
				return
			}
			fmt.Printf("Readed bytes: %d\n", n)
			b := buff[:n]
			//write out result
			n, err = dst.Write(b)
			if err != nil {
				p.err("Write failed '%s'\n", err)
				return
			}

			r = buff[:n]
			// fmt.Printf("%#v", string(buff[:n]))
			if remainingBytes > 0 {
				if remainingBytes <= n {
					newPacket = true
					msg = msg + string(r.next(remainingBytes))
					remainingBytes = n - remainingBytes
					fmt.Println("msg: ", string(msg))
				} else {
					newPacket = false
					msg = msg + string(r.next(remainingBytes))
					remainingBytes = remainingBytes - n
				}
			}
			fmt.Printf("Remaining bytes: %d\n", remainingBytes)
		NewP:
			if newPacket {
				remainingBytes = 0
				newPacket = false
				msg = ""
				t := r.byte()
				n = n - 1
				fmt.Println(t)
				switch t {
				case query:
					// c.rxReadyForQuery(r)
					remainingBytes = r.int32()
					remainingBytes = remainingBytes - 4
					if remainingBytes > 0 {
						if remainingBytes <= n {
							newPacket = true
							msg = msg + string(r.next(remainingBytes))
							remainingBytes = n - remainingBytes
							fmt.Println(msg)
							goto NewP
						} else {
							newPacket = false
							msg = msg + string(r.next(remainingBytes))
							remainingBytes = remainingBytes - n
						}
						fmt.Printf("Remaining bytes: %d\n", remainingBytes)
					}
				// case rowDescription:
				// case dataRow:
				// case bindComplete:
				// case commandComplete:
				// 	commandTag = CommandTag(r.readCString())
				default:
					// if e := c.processContextFreeMsg(t, r); e != nil && softErr == nil {
					// 	softErr = e
					// }
				}
			}
			// r = append(r, buff[:]...)

			// fmt.Println("a")
			// c := src
			// c.reader = bufio.NewReader(src.conn)
			// c.mr.reader = c.reader
			//
			// var t byte
			// var r *msgReader
			// fmt.Println("b")
			// t, r, err := c.rxMsg()
			// fmt.Println("c")
			// if err != nil {
			// 	fmt.Println(err)
			// 	return
			// }
			// fmt.Println("d")
			//
			// fmt.Printf("t: %#v\n", t)

			// n, err := src.Read(buff)
			// if err != nil {
			// 	p.err("Read failed '%s'\n", err)
			// 	return
			// }
			// b := buff[:n]
			// //show output
			//
			//
			// b = getModifiedBuffer(b, powerCallback)
			// n, err = dst.Write(b)
			// //
			// //write out result
			// n, err = dst.Write(b)
			// if err != nil {
			// 	p.err("Write failed '%s'\n", err)
			// 	return
			// }
		}
	} else {
		for {
			n, err := src.Read(buff)
			if err != nil {
				p.err("Read failed '%s'\n", err)
				return
			}
			b := buff[:n]
			//write out result
			n, err = dst.Write(b)
			if err != nil {
				p.err("Write failed '%s'\n", err)
				return
			}
			if err != nil {
				p.err("Write failed '%s'\n", err)
				return
			}
		}
	}
}

func getModifiedBuffer(buffer []byte, powerCallback common.Callback) []byte {
	if powerCallback == nil || len(buffer) < 1 || string(buffer[0]) != "Q" || string(buffer[5:11]) != "power:" {
		return buffer
	}
	query := powerCallback(string(buffer[5:]))
	return makeMessage(query)
}

func makeMessage(query string) []byte {
	queryArray := make([]byte, 0, 6+len(query))
	queryArray = append(queryArray, 'Q', 0, 0, 0, 0)
	queryArray = append(queryArray, query...)
	queryArray = append(queryArray, 0)
	binary.BigEndian.PutUint32(queryArray[1:], uint32(len(queryArray)-1))
	return queryArray

}

func check(err error) {
	if err != nil {
		warn(err.Error())
		os.Exit(1)
	}
}

func warn(f string, args ...interface{}) {
	fmt.Printf(f+"\n", args...)
}
<|endoftext|>


<commit_before>package proxy

import (
	"log"
	"time"
	"errors"
	"math/rand"
	"net"
	"net/http"
)

type Proxy struct {
	addr *net.TCPAddr
	conn *net.TCPConn
}

var proxies []*Proxy

//remote, err := proxy.SelectFromRequest(req)
//return remote.GetConn()

func AddProxy(addr string) error {
	proxy, err := New(addr)
	if err != nil {
		return err
	}

	proxies = append(proxies, proxy)
	return nil
}

func SelectRandom() (*Proxy, error) {
	rand.Seed(time.Now().Unix())

	r := rand.Intn(len(proxies))

	log.Printf("Random : %v with \n", r, proxies[r].addr.String())
	return proxies[r], nil
}

func SelectFromRequest(request *http.Request) (*Proxy, error) {
	return nil, errors.New("SelectFromRequest not implemented")
}

func New(addr string) (*Proxy, error) {
	_addr, err := net.ResolveTCPAddr("tcp", addr)
	if err != nil {
		return nil, err
	}

	p := Proxy {
		addr: _addr,
		conn: nil,
	}
	return &p, nil
}

func (p *Proxy)Close() {
	p.conn.Close()
	p.conn = nil
}

func (p *Proxy)GetConn() (*net.TCPConn, error) {
	if p.conn == nil {
		_conn, err := net.DialTCP("tcp", nil, p.addr)
		if err != nil {
			return nil, err
		}
		p.conn = _conn
	}
	return p.conn, nil
}
<commit_msg>Typo fix.<commit_after>package proxy

import (
	"time"
	"errors"
	"math/rand"
	"net"
	"net/http"
)

type Proxy struct {
	addr *net.TCPAddr
	conn *net.TCPConn
}

var proxies []*Proxy

func AddProxy(addr string) error {
	proxy, err := New(addr)
	if err != nil {
		return err
	}

	proxies = append(proxies, proxy)
	return nil
}

func SelectRandom() (*Proxy, error) {
	rand.Seed(time.Now().Unix())

	r := rand.Intn(len(proxies))

	return proxies[r], nil
}

func SelectFromRequest(request *http.Request) (*Proxy, error) {
	return nil, errors.New("SelectFromRequest not implemented")
}

func New(addr string) (*Proxy, error) {
	_addr, err := net.ResolveTCPAddr("tcp", addr)
	if err != nil {
		return nil, err
	}

	p := Proxy {
		addr: _addr,
		conn: nil,
	}
	return &p, nil
}

func (p *Proxy)Close() {
	p.conn.Close()
	p.conn = nil
}

func (p *Proxy)GetConn() (*net.TCPConn, error) {
	if p.conn == nil {
		_conn, err := net.DialTCP("tcp", nil, p.addr)
		if err != nil {
			return nil, err
		}
		p.conn = _conn
	}
	return p.conn, nil
}
<|endoftext|>


<commit_before>package out

import (
	"github.com/idahobean/npm-resource"
	"github.com/idahobean/npm-resource/npm"
	"path/filepath"
	"os"
)

type Command struct {
	packageManager npm.PackageManager
}

func NewCommand(packageManager npm.PackageManager) *Command {
	return &Command{
		packageManager: packageManager,
	}
}

func (command *Command) Run(request Request) (Response, error) {
	err := command.packageManager.Login(
		request.Params.UserName,
		request.Params.Password,
		request.Params.Email,
		request.Source.Registry,
	)
	if err != nil {
		return Response{}, err
	}

	path, err := filepath.Abs(filepath.Dir(os.Args[0]))
	if err != nil {
		return Response{}, err
	}

	err := command.packageManager.Publish(
		filepath.Join(path, request.Params.Path),
		request.Params.Tag,
		request.Source.Registry,
	)
	if err != nil {
		return Response{}, err
	}

	out, err := command.packageManager.View(
		request.Source.PackageName,
		request.Source.Registry,
	)
	if err != nil {
		return Response{}, err
	}

	err := command.packageManager.Logout(
		request.Source.Registry,
	)
	if err != nil {
		return Response{}, err
	}

	return Response{
		Version: resource.Version{
			Version: out.Version,
		},
		Metadata: []resource.MetadataPair{
			{
				Name:  "name",
				Value: out.Name,
			},
			{
				Name:  "homepage",
				Value: out.Homepage,
			},
		},
	}, nil
}
<commit_msg>remove unnecessary colons<commit_after>package out

import (
	"github.com/idahobean/npm-resource"
	"github.com/idahobean/npm-resource/npm"
	"path/filepath"
	"os"
)

type Command struct {
	packageManager npm.PackageManager
}

func NewCommand(packageManager npm.PackageManager) *Command {
	return &Command{
		packageManager: packageManager,
	}
}

func (command *Command) Run(request Request) (Response, error) {
	err := command.packageManager.Login(
		request.Params.UserName,
		request.Params.Password,
		request.Params.Email,
		request.Source.Registry,
	)
	if err != nil {
		return Response{}, err
	}

	path, err := filepath.Abs(filepath.Dir(os.Args[0]))
	if err != nil {
		return Response{}, err
	}

	err = command.packageManager.Publish(
		filepath.Join(path, request.Params.Path),
		request.Params.Tag,
		request.Source.Registry,
	)
	if err != nil {
		return Response{}, err
	}

	out, err := command.packageManager.View(
		request.Source.PackageName,
		request.Source.Registry,
	)
	if err != nil {
		return Response{}, err
	}

	err = command.packageManager.Logout(
		request.Source.Registry,
	)
	if err != nil {
		return Response{}, err
	}

	return Response{
		Version: resource.Version{
			Version: out.Version,
		},
		Metadata: []resource.MetadataPair{
			{
				Name:  "name",
				Value: out.Name,
			},
			{
				Name:  "homepage",
				Value: out.Homepage,
			},
		},
	}, nil
}
<|endoftext|>