<commit_before>// Copyright 2011 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 dsa implements the Digital Signature Algorithm, as defined in FIPS 186-3
package dsa

import (
	"errors"
	"io"
	"math/big"
)

// Parameters represents the domain parameters for a key. These parameters can
// be shared across many keys. The bit length of Q must be a multiple of 8.
type Parameters struct {
	P, Q, G *big.Int
}

// PublicKey represents a DSA public key.
type PublicKey struct {
	Parameters
	Y *big.Int
}

// PrivateKey represents a DSA private key.
type PrivateKey struct {
	PublicKey
	X *big.Int
}

type invalidPublicKeyError int

func (invalidPublicKeyError) Error() string {
	return "crypto/dsa: invalid public key"
}

// InvalidPublicKeyError results when a public key is not usable by this code.
// FIPS is quite strict about the format of DSA keys, but other code may be
// less so. Thus, when using keys which may have been generated by other code,
// this error must be handled.
var InvalidPublicKeyError = invalidPublicKeyError(0)

// ParameterSizes is a enumeration of the acceptable bit lengths of the primes
// in a set of DSA parameters. See FIPS 186-3, section 4.2.
type ParameterSizes int

const (
	L1024N160 ParameterSizes = iota
	L2048N224
	L2048N256
	L3072N256
)

// numMRTests is the number of Miller-Rabin primality tests that we perform. We
// pick the largest recommended number from table C.1 of FIPS 186-3.
const numMRTests = 64

// GenerateParameters puts a random, valid set of DSA parameters into params.
// This function takes many seconds, even on fast machines.
func GenerateParameters(params *Parameters, rand io.Reader, sizes ParameterSizes) (err error) {
	// This function doesn't follow FIPS 186-3 exactly in that it doesn't
	// use a verification seed to generate the primes. The verification
	// seed doesn't appear to be exported or used by other code and
	// omitting it makes the code cleaner.

	var L, N int
	switch sizes {
	case L1024N160:
		L = 1024
		N = 160
	case L2048N224:
		L = 2048
		N = 224
	case L2048N256:
		L = 2048
		N = 256
	case L3072N256:
		L = 3072
		N = 256
	default:
		return errors.New("crypto/dsa: invalid ParameterSizes")
	}

	qBytes := make([]byte, N/8)
	pBytes := make([]byte, L/8)

	q := new(big.Int)
	p := new(big.Int)
	rem := new(big.Int)
	one := new(big.Int)
	one.SetInt64(1)

GeneratePrimes:
	for {
		_, err = io.ReadFull(rand, qBytes)
		if err != nil {
			return
		}

		qBytes[len(qBytes)-1] |= 1
		qBytes[0] |= 0x80
		q.SetBytes(qBytes)

		if !big.ProbablyPrime(q, numMRTests) {
			continue
		}

		for i := 0; i < 4*L; i++ {
			_, err = io.ReadFull(rand, pBytes)
			if err != nil {
				return
			}

			pBytes[len(pBytes)-1] |= 1
			pBytes[0] |= 0x80

			p.SetBytes(pBytes)
			rem.Mod(p, q)
			rem.Sub(rem, one)
			p.Sub(p, rem)
			if p.BitLen() < L {
				continue
			}

			if !big.ProbablyPrime(p, numMRTests) {
				continue
			}

			params.P = p
			params.Q = q
			break GeneratePrimes
		}
	}

	h := new(big.Int)
	h.SetInt64(2)
	g := new(big.Int)

	pm1 := new(big.Int).Sub(p, one)
	e := new(big.Int).Div(pm1, q)

	for {
		g.Exp(h, e, p)
		if g.Cmp(one) == 0 {
			h.Add(h, one)
			continue
		}

		params.G = g
		return
	}

	panic("unreachable")
}

// GenerateKey generates a public&private key pair. The Parameters of the
// PrivateKey must already be valid (see GenerateParameters).
func GenerateKey(priv *PrivateKey, rand io.Reader) error {
	if priv.P == nil || priv.Q == nil || priv.G == nil {
		return errors.New("crypto/dsa: parameters not set up before generating key")
	}

	x := new(big.Int)
	xBytes := make([]byte, priv.Q.BitLen()/8)

	for {
		_, err := io.ReadFull(rand, xBytes)
		if err != nil {
			return err
		}
		x.SetBytes(xBytes)
		if x.Sign() != 0 && x.Cmp(priv.Q) < 0 {
			break
		}
	}

	priv.X = x
	priv.Y = new(big.Int)
	priv.Y.Exp(priv.G, x, priv.P)
	return nil
}

// Sign signs an arbitrary length hash (which should be the result of hashing a
// larger message) using the private key, priv. It returns the signature as a
// pair of integers. The security of the private key depends on the entropy of
// rand.
func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err error) {
	// FIPS 186-3, section 4.6

	n := priv.Q.BitLen()
	if n&7 != 0 {
		err = InvalidPublicKeyError
		return
	}
	n >>= 3

	for {
		k := new(big.Int)
		buf := make([]byte, n)
		for {
			_, err = io.ReadFull(rand, buf)
			if err != nil {
				return
			}
			k.SetBytes(buf)
			if k.Sign() > 0 && k.Cmp(priv.Q) < 0 {
				break
			}
		}

		kInv := new(big.Int).ModInverse(k, priv.Q)

		r = new(big.Int).Exp(priv.G, k, priv.P)
		r.Mod(r, priv.Q)

		if r.Sign() == 0 {
			continue
		}

		if n > len(hash) {
			n = len(hash)
		}
		z := k.SetBytes(hash[:n])

		s = new(big.Int).Mul(priv.X, r)
		s.Add(s, z)
		s.Mod(s, priv.Q)
		s.Mul(s, kInv)
		s.Mod(s, priv.Q)

		if s.Sign() != 0 {
			break
		}
	}

	return
}

// Verify verifies the signature in r, s of hash using the public key, pub. It
// returns true iff the signature is valid.
func Verify(pub *PublicKey, hash []byte, r, s *big.Int) bool {
	// FIPS 186-3, section 4.7

	if r.Sign() < 1 || r.Cmp(pub.Q) >= 0 {
		return false
	}
	if s.Sign() < 1 || s.Cmp(pub.Q) >= 0 {
		return false
	}

	w := new(big.Int).ModInverse(s, pub.Q)

	n := pub.Q.BitLen()
	if n&7 != 0 {
		return false
	}
	n >>= 3

	if n > len(hash) {
		n = len(hash)
	}
	z := new(big.Int).SetBytes(hash[:n])

	u1 := new(big.Int).Mul(z, w)
	u1.Mod(u1, pub.Q)
	u2 := w.Mul(r, w)
	u2.Mod(u2, pub.Q)
	v := u1.Exp(pub.G, u1, pub.P)
	u2.Exp(pub.Y, u2, pub.P)
	v.Mul(v, u2)
	v.Mod(v, pub.P)
	v.Mod(v, pub.Q)

	return v.Cmp(r) == 0
}
<commit_msg>crypto/dsa: don't truncate input hashes.<commit_after>// Copyright 2011 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 dsa implements the Digital Signature Algorithm, as defined in FIPS 186-3
package dsa

import (
	"errors"
	"io"
	"math/big"
)

// Parameters represents the domain parameters for a key. These parameters can
// be shared across many keys. The bit length of Q must be a multiple of 8.
type Parameters struct {
	P, Q, G *big.Int
}

// PublicKey represents a DSA public key.
type PublicKey struct {
	Parameters
	Y *big.Int
}

// PrivateKey represents a DSA private key.
type PrivateKey struct {
	PublicKey
	X *big.Int
}

type invalidPublicKeyError int

func (invalidPublicKeyError) Error() string {
	return "crypto/dsa: invalid public key"
}

// InvalidPublicKeyError results when a public key is not usable by this code.
// FIPS is quite strict about the format of DSA keys, but other code may be
// less so. Thus, when using keys which may have been generated by other code,
// this error must be handled.
var InvalidPublicKeyError = invalidPublicKeyError(0)

// ParameterSizes is a enumeration of the acceptable bit lengths of the primes
// in a set of DSA parameters. See FIPS 186-3, section 4.2.
type ParameterSizes int

const (
	L1024N160 ParameterSizes = iota
	L2048N224
	L2048N256
	L3072N256
)

// numMRTests is the number of Miller-Rabin primality tests that we perform. We
// pick the largest recommended number from table C.1 of FIPS 186-3.
const numMRTests = 64

// GenerateParameters puts a random, valid set of DSA parameters into params.
// This function takes many seconds, even on fast machines.
func GenerateParameters(params *Parameters, rand io.Reader, sizes ParameterSizes) (err error) {
	// This function doesn't follow FIPS 186-3 exactly in that it doesn't
	// use a verification seed to generate the primes. The verification
	// seed doesn't appear to be exported or used by other code and
	// omitting it makes the code cleaner.

	var L, N int
	switch sizes {
	case L1024N160:
		L = 1024
		N = 160
	case L2048N224:
		L = 2048
		N = 224
	case L2048N256:
		L = 2048
		N = 256
	case L3072N256:
		L = 3072
		N = 256
	default:
		return errors.New("crypto/dsa: invalid ParameterSizes")
	}

	qBytes := make([]byte, N/8)
	pBytes := make([]byte, L/8)

	q := new(big.Int)
	p := new(big.Int)
	rem := new(big.Int)
	one := new(big.Int)
	one.SetInt64(1)

GeneratePrimes:
	for {
		_, err = io.ReadFull(rand, qBytes)
		if err != nil {
			return
		}

		qBytes[len(qBytes)-1] |= 1
		qBytes[0] |= 0x80
		q.SetBytes(qBytes)

		if !big.ProbablyPrime(q, numMRTests) {
			continue
		}

		for i := 0; i < 4*L; i++ {
			_, err = io.ReadFull(rand, pBytes)
			if err != nil {
				return
			}

			pBytes[len(pBytes)-1] |= 1
			pBytes[0] |= 0x80

			p.SetBytes(pBytes)
			rem.Mod(p, q)
			rem.Sub(rem, one)
			p.Sub(p, rem)
			if p.BitLen() < L {
				continue
			}

			if !big.ProbablyPrime(p, numMRTests) {
				continue
			}

			params.P = p
			params.Q = q
			break GeneratePrimes
		}
	}

	h := new(big.Int)
	h.SetInt64(2)
	g := new(big.Int)

	pm1 := new(big.Int).Sub(p, one)
	e := new(big.Int).Div(pm1, q)

	for {
		g.Exp(h, e, p)
		if g.Cmp(one) == 0 {
			h.Add(h, one)
			continue
		}

		params.G = g
		return
	}

	panic("unreachable")
}

// GenerateKey generates a public&private key pair. The Parameters of the
// PrivateKey must already be valid (see GenerateParameters).
func GenerateKey(priv *PrivateKey, rand io.Reader) error {
	if priv.P == nil || priv.Q == nil || priv.G == nil {
		return errors.New("crypto/dsa: parameters not set up before generating key")
	}

	x := new(big.Int)
	xBytes := make([]byte, priv.Q.BitLen()/8)

	for {
		_, err := io.ReadFull(rand, xBytes)
		if err != nil {
			return err
		}
		x.SetBytes(xBytes)
		if x.Sign() != 0 && x.Cmp(priv.Q) < 0 {
			break
		}
	}

	priv.X = x
	priv.Y = new(big.Int)
	priv.Y.Exp(priv.G, x, priv.P)
	return nil
}

// Sign signs an arbitrary length hash (which should be the result of hashing a
// larger message) using the private key, priv. It returns the signature as a
// pair of integers. The security of the private key depends on the entropy of
// rand.
//
// Note that FIPS 186-3 section 4.6 specifies that the hash should be truncated
// to the byte-length of the subgroup. This function does not perform that
// truncation itself.
func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err error) {
	// FIPS 186-3, section 4.6

	n := priv.Q.BitLen()
	if n&7 != 0 {
		err = InvalidPublicKeyError
		return
	}
	n >>= 3

	for {
		k := new(big.Int)
		buf := make([]byte, n)
		for {
			_, err = io.ReadFull(rand, buf)
			if err != nil {
				return
			}
			k.SetBytes(buf)
			if k.Sign() > 0 && k.Cmp(priv.Q) < 0 {
				break
			}
		}

		kInv := new(big.Int).ModInverse(k, priv.Q)

		r = new(big.Int).Exp(priv.G, k, priv.P)
		r.Mod(r, priv.Q)

		if r.Sign() == 0 {
			continue
		}

		z := k.SetBytes(hash)

		s = new(big.Int).Mul(priv.X, r)
		s.Add(s, z)
		s.Mod(s, priv.Q)
		s.Mul(s, kInv)
		s.Mod(s, priv.Q)

		if s.Sign() != 0 {
			break
		}
	}

	return
}

// Verify verifies the signature in r, s of hash using the public key, pub. It
// reports whether the signature is valid.
//
// Note that FIPS 186-3 section 4.6 specifies that the hash should be truncated
// to the byte-length of the subgroup. This function does not perform that
// truncation itself.
func Verify(pub *PublicKey, hash []byte, r, s *big.Int) bool {
	// FIPS 186-3, section 4.7

	if r.Sign() < 1 || r.Cmp(pub.Q) >= 0 {
		return false
	}
	if s.Sign() < 1 || s.Cmp(pub.Q) >= 0 {
		return false
	}

	w := new(big.Int).ModInverse(s, pub.Q)

	n := pub.Q.BitLen()
	if n&7 != 0 {
		return false
	}
	z := new(big.Int).SetBytes(hash)

	u1 := new(big.Int).Mul(z, w)
	u1.Mod(u1, pub.Q)
	u2 := w.Mul(r, w)
	u2.Mod(u2, pub.Q)
	v := u1.Exp(pub.G, u1, pub.P)
	u2.Exp(pub.Y, u2, pub.P)
	v.Mul(v, u2)
	v.Mod(v, pub.P)
	v.Mod(v, pub.Q)

	return v.Cmp(r) == 0
}
<|endoftext|>


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

package draw

// A Point is an X, Y coordinate pair.
type Point struct {
	X, Y int
}

// ZP is the zero Point.
var ZP Point

// A Rectangle contains the Points with Min.X <= X < Max.X, Min.Y <= Y < Max.Y.
type Rectangle struct {
	Min, Max Point
}

// ZR is the zero Rectangle.
var ZR Rectangle

// Pt is shorthand for Point{X, Y}.
func Pt(X, Y int) Point { return Point{X, Y} }

// Rect is shorthand for Rectangle{Pt(x0, y0), Pt(x1, y1)}.
func Rect(x0, y0, x1, y1 int) Rectangle { return Rectangle{Point{x0, y0}, Point{x1, y1}} }

// Rpt is shorthand for Rectangle{min, max}.
func Rpt(min, max Point) Rectangle { return Rectangle{min, max} }

// Add returns the sum of p and q: Pt(p.X+q.X, p.Y+q.Y).
func (p Point) Add(q Point) Point { return Point{p.X + q.X, p.Y + q.Y} }

// Sub returns the difference of p and q: Pt(p.X-q.X, p.Y-q.Y).
func (p Point) Sub(q Point) Point { return Point{p.X - q.X, p.Y - q.Y} }

// Mul returns p scaled by k: Pt(p.X*k p.Y*k).
func (p Point) Mul(k int) Point { return Point{p.X * k, p.Y * k} }

// Div returns p divided by k: Pt(p.X/k, p.Y/k).
func (p Point) Div(k int) Point { return Point{p.X / k, p.Y / k} }

// Eq returns true if p and q are equal.
func (p Point) Eq(q Point) bool { return p.X == q.X && p.Y == q.Y }

// Inset returns the rectangle r inset by n: Rect(r.Min.X+n, r.Min.Y+n, r.Max.X-n, r.Max.Y-n).
func (r Rectangle) Inset(n int) Rectangle {
	return Rectangle{Point{r.Min.X + n, r.Min.Y + n}, Point{r.Max.X - n, r.Max.Y - n}}
}

// Add returns the rectangle r translated by p: Rpt(r.Min.Add(p), r.Max.Add(p)).
func (r Rectangle) Add(p Point) Rectangle { return Rectangle{r.Min.Add(p), r.Max.Add(p)} }

// Sub returns the rectangle r translated by -p: Rpt(r.Min.Sub(p), r.Max.Sub(p)).
func (r Rectangle) Sub(p Point) Rectangle { return Rectangle{r.Min.Sub(p), r.Max.Sub(p)} }

// Canon returns a canonical version of r: the returned rectangle
// has Min.X <= Max.X and Min.Y <= Max.Y.
func (r Rectangle) Canon() Rectangle {
	if r.Max.X < r.Min.X {
		r.Max.X = r.Min.X
	}
	if r.Max.Y < r.Min.Y {
		r.Max.Y = r.Min.Y
	}
	return r
}

// Overlaps returns true if r and r1 cross; that is, it returns true if they share any point.
func (r Rectangle) Overlaps(r1 Rectangle) bool {
	return r.Min.X < r1.Max.X && r1.Min.X < r.Max.X &&
		r.Min.Y < r1.Max.Y && r1.Min.Y < r.Max.Y
}

// Empty retruns true if r contains no points.
func (r Rectangle) Empty() bool { return r.Max.X <= r.Min.X || r.Max.Y <= r.Min.Y }

// InRect returns true if all the points in r are also in r1.
func (r Rectangle) In(r1 Rectangle) bool {
	if r.Empty() {
		return true
	}
	if r1.Empty() {
		return false
	}
	return r1.Min.X <= r.Min.X && r.Max.X <= r1.Max.X &&
		r1.Min.Y <= r.Min.Y && r.Max.Y <= r1.Max.Y
}

// Combine returns the smallest rectangle containing all points from r and from r1.
func (r Rectangle) Combine(r1 Rectangle) Rectangle {
	if r.Empty() {
		return r1
	}
	if r1.Empty() {
		return r
	}
	if r.Min.X > r1.Min.X {
		r.Min.X = r1.Min.X
	}
	if r.Min.Y > r1.Min.Y {
		r.Min.Y = r1.Min.Y
	}
	if r.Max.X < r1.Max.X {
		r.Max.X = r1.Max.X
	}
	if r.Max.Y < r1.Max.Y {
		r.Max.Y = r1.Max.Y
	}
	return r
}

// Clip returns the largest rectangle containing only points shared by r and r1.
func (r Rectangle) Clip(r1 Rectangle) Rectangle {
	if r.Empty() {
		return r
	}
	if r1.Empty() {
		return r1
	}
	if r.Min.X < r1.Min.X {
		r.Min.X = r1.Min.X
	}
	if r.Min.Y < r1.Min.Y {
		r.Min.Y = r1.Min.Y
	}
	if r.Max.X > r1.Max.X {
		r.Max.X = r1.Max.X
	}
	if r.Max.Y > r1.Max.Y {
		r.Max.Y = r1.Max.Y
	}
	return r
}

// Dx returns the width of the rectangle r: r.Max.X - r.Min.X.
func (r Rectangle) Dx() int { return r.Max.X - r.Min.X }

// Dy returns the width of the rectangle r: r.Max.Y - r.Min.Y.
func (r Rectangle) Dy() int { return r.Max.Y - r.Min.Y }
<commit_msg>Fix Rectangle.Canon()<commit_after>// Copyright 2009 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package draw

// A Point is an X, Y coordinate pair.
type Point struct {
	X, Y int
}

// ZP is the zero Point.
var ZP Point

// A Rectangle contains the Points with Min.X <= X < Max.X, Min.Y <= Y < Max.Y.
type Rectangle struct {
	Min, Max Point
}

// ZR is the zero Rectangle.
var ZR Rectangle

// Pt is shorthand for Point{X, Y}.
func Pt(X, Y int) Point { return Point{X, Y} }

// Rect is shorthand for Rectangle{Pt(x0, y0), Pt(x1, y1)}.
func Rect(x0, y0, x1, y1 int) Rectangle { return Rectangle{Point{x0, y0}, Point{x1, y1}} }

// Rpt is shorthand for Rectangle{min, max}.
func Rpt(min, max Point) Rectangle { return Rectangle{min, max} }

// Add returns the sum of p and q: Pt(p.X+q.X, p.Y+q.Y).
func (p Point) Add(q Point) Point { return Point{p.X + q.X, p.Y + q.Y} }

// Sub returns the difference of p and q: Pt(p.X-q.X, p.Y-q.Y).
func (p Point) Sub(q Point) Point { return Point{p.X - q.X, p.Y - q.Y} }

// Mul returns p scaled by k: Pt(p.X*k p.Y*k).
func (p Point) Mul(k int) Point { return Point{p.X * k, p.Y * k} }

// Div returns p divided by k: Pt(p.X/k, p.Y/k).
func (p Point) Div(k int) Point { return Point{p.X / k, p.Y / k} }

// Eq returns true if p and q are equal.
func (p Point) Eq(q Point) bool { return p.X == q.X && p.Y == q.Y }

// Inset returns the rectangle r inset by n: Rect(r.Min.X+n, r.Min.Y+n, r.Max.X-n, r.Max.Y-n).
func (r Rectangle) Inset(n int) Rectangle {
	return Rectangle{Point{r.Min.X + n, r.Min.Y + n}, Point{r.Max.X - n, r.Max.Y - n}}
}

// Add returns the rectangle r translated by p: Rpt(r.Min.Add(p), r.Max.Add(p)).
func (r Rectangle) Add(p Point) Rectangle { return Rectangle{r.Min.Add(p), r.Max.Add(p)} }

// Sub returns the rectangle r translated by -p: Rpt(r.Min.Sub(p), r.Max.Sub(p)).
func (r Rectangle) Sub(p Point) Rectangle { return Rectangle{r.Min.Sub(p), r.Max.Sub(p)} }

// Canon returns a canonical version of r: the returned rectangle
// has Min.X <= Max.X and Min.Y <= Max.Y.
func (r Rectangle) Canon() Rectangle {
	if r.Max.X < r.Min.X {
		r.Min.X, r.Max.X = r.Max.X, r.Min.X
	}
	if r.Max.Y < r.Min.Y {
		r.Min.Y, r.Max.Y = r.Max.Y, r.Min.Y
	}
	return r
}

// Overlaps returns true if r and r1 cross; that is, it returns true if they share any point.
func (r Rectangle) Overlaps(r1 Rectangle) bool {
	return r.Min.X < r1.Max.X && r1.Min.X < r.Max.X &&
		r.Min.Y < r1.Max.Y && r1.Min.Y < r.Max.Y
}

// Empty retruns true if r contains no points.
func (r Rectangle) Empty() bool { return r.Max.X <= r.Min.X || r.Max.Y <= r.Min.Y }

// InRect returns true if all the points in r are also in r1.
func (r Rectangle) In(r1 Rectangle) bool {
	if r.Empty() {
		return true
	}
	if r1.Empty() {
		return false
	}
	return r1.Min.X <= r.Min.X && r.Max.X <= r1.Max.X &&
		r1.Min.Y <= r.Min.Y && r.Max.Y <= r1.Max.Y
}

// Combine returns the smallest rectangle containing all points from r and from r1.
func (r Rectangle) Combine(r1 Rectangle) Rectangle {
	if r.Empty() {
		return r1
	}
	if r1.Empty() {
		return r
	}
	if r.Min.X > r1.Min.X {
		r.Min.X = r1.Min.X
	}
	if r.Min.Y > r1.Min.Y {
		r.Min.Y = r1.Min.Y
	}
	if r.Max.X < r1.Max.X {
		r.Max.X = r1.Max.X
	}
	if r.Max.Y < r1.Max.Y {
		r.Max.Y = r1.Max.Y
	}
	return r
}

// Clip returns the largest rectangle containing only points shared by r and r1.
func (r Rectangle) Clip(r1 Rectangle) Rectangle {
	if r.Empty() {
		return r
	}
	if r1.Empty() {
		return r1
	}
	if r.Min.X < r1.Min.X {
		r.Min.X = r1.Min.X
	}
	if r.Min.Y < r1.Min.Y {
		r.Min.Y = r1.Min.Y
	}
	if r.Max.X > r1.Max.X {
		r.Max.X = r1.Max.X
	}
	if r.Max.Y > r1.Max.Y {
		r.Max.Y = r1.Max.Y
	}
	return r
}

// Dx returns the width of the rectangle r: r.Max.X - r.Min.X.
func (r Rectangle) Dx() int { return r.Max.X - r.Min.X }

// Dy returns the width of the rectangle r: r.Max.Y - r.Min.Y.
func (r Rectangle) Dy() int { return r.Max.Y - r.Min.Y }
<|endoftext|>


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

// Waiting for FDs via kqueue/kevent.

package net

import (
	"os"
	"syscall"
)

type pollster struct {
	kq       int
	eventbuf [10]syscall.Kevent_t
	events   []syscall.Kevent_t
}

func newpollster() (p *pollster, err os.Error) {
	p = new(pollster)
	var e int
	if p.kq, e = syscall.Kqueue(); e != 0 {
		return nil, os.NewSyscallError("kqueue", e)
	}
	p.events = p.eventbuf[0:0]
	return p, nil
}

func (p *pollster) AddFD(fd int, mode int, repeat bool) os.Error {
	var kmode int
	if mode == 'r' {
		kmode = syscall.EVFILT_READ
	} else {
		kmode = syscall.EVFILT_WRITE
	}
	var events [1]syscall.Kevent_t
	ev := &events[0]
	// EV_ADD - add event to kqueue list
	// EV_ONESHOT - delete the event the first time it triggers
	flags := syscall.EV_ADD
	if !repeat {
		flags |= syscall.EV_ONESHOT
	}
	syscall.SetKevent(ev, fd, kmode, flags)

	n, e := syscall.Kevent(p.kq, &events, nil, nil)
	if e != 0 {
		return os.NewSyscallError("kevent", e)
	}
	if n != 1 || (ev.Flags&syscall.EV_ERROR) == 0 || int(ev.Ident) != fd || int(ev.Filter) != kmode {
		return os.NewSyscallError("kqueue phase error", e)
	}
	if ev.Data != 0 {
		return os.Errno(int(ev.Data))
	}
	return nil
}

func (p *pollster) DelFD(fd int, mode int) {
	var kmode int
	if mode == 'r' {
		kmode = syscall.EVFILT_READ
	} else {
		kmode = syscall.EVFILT_WRITE
	}
	var events [1]syscall.Kevent_t
	ev := &events[0]
	// EV_DELETE - delete event from kqueue list
	syscall.SetKevent(ev, fd, kmode, syscall.EV_DELETE)
	syscall.Kevent(p.kq, &events, nil, nil)
}

func (p *pollster) WaitFD(nsec int64) (fd int, mode int, err os.Error) {
	var t *syscall.Timespec
	for len(p.events) == 0 {
		if nsec > 0 {
			if t == nil {
				t = new(syscall.Timespec)
			}
			*t = syscall.NsecToTimespec(nsec)
		}
		nn, e := syscall.Kevent(p.kq, nil, &p.eventbuf, t)
		if e != 0 {
			if e == syscall.EINTR {
				continue
			}
			return -1, 0, os.NewSyscallError("kevent", e)
		}
		if nn == 0 {
			return -1, 0, nil
		}
		p.events = p.eventbuf[0:nn]
	}
	ev := &p.events[0]
	p.events = p.events[1:]
	fd = int(ev.Ident)
	if ev.Filter == syscall.EVFILT_READ {
		mode = 'r'
	} else {
		mode = 'w'
	}
	return fd, mode, nil
}

func (p *pollster) Close() os.Error { return os.NewSyscallError("close", syscall.Close(p.kq)) }
<commit_msg>net: fix freebsd build<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Waiting for FDs via kqueue/kevent.

package net

import (
	"os"
	"syscall"
)

type pollster struct {
	kq       int
	eventbuf [10]syscall.Kevent_t
	events   []syscall.Kevent_t
}

func newpollster() (p *pollster, err os.Error) {
	p = new(pollster)
	var e int
	if p.kq, e = syscall.Kqueue(); e != 0 {
		return nil, os.NewSyscallError("kqueue", e)
	}
	p.events = p.eventbuf[0:0]
	return p, nil
}

func (p *pollster) AddFD(fd int, mode int, repeat bool) os.Error {
	var kmode int
	if mode == 'r' {
		kmode = syscall.EVFILT_READ
	} else {
		kmode = syscall.EVFILT_WRITE
	}
	var events [1]syscall.Kevent_t
	ev := &events[0]
	// EV_ADD - add event to kqueue list
	// EV_ONESHOT - delete the event the first time it triggers
	flags := syscall.EV_ADD
	if !repeat {
		flags |= syscall.EV_ONESHOT
	}
	syscall.SetKevent(ev, fd, kmode, flags)

	n, e := syscall.Kevent(p.kq, events[:], nil, nil)
	if e != 0 {
		return os.NewSyscallError("kevent", e)
	}
	if n != 1 || (ev.Flags&syscall.EV_ERROR) == 0 || int(ev.Ident) != fd || int(ev.Filter) != kmode {
		return os.NewSyscallError("kqueue phase error", e)
	}
	if ev.Data != 0 {
		return os.Errno(int(ev.Data))
	}
	return nil
}

func (p *pollster) DelFD(fd int, mode int) {
	var kmode int
	if mode == 'r' {
		kmode = syscall.EVFILT_READ
	} else {
		kmode = syscall.EVFILT_WRITE
	}
	var events [1]syscall.Kevent_t
	ev := &events[0]
	// EV_DELETE - delete event from kqueue list
	syscall.SetKevent(ev, fd, kmode, syscall.EV_DELETE)
	syscall.Kevent(p.kq, events[:], nil, nil)
}

func (p *pollster) WaitFD(nsec int64) (fd int, mode int, err os.Error) {
	var t *syscall.Timespec
	for len(p.events) == 0 {
		if nsec > 0 {
			if t == nil {
				t = new(syscall.Timespec)
			}
			*t = syscall.NsecToTimespec(nsec)
		}
		nn, e := syscall.Kevent(p.kq, nil, p.eventbuf[:], t)
		if e != 0 {
			if e == syscall.EINTR {
				continue
			}
			return -1, 0, os.NewSyscallError("kevent", e)
		}
		if nn == 0 {
			return -1, 0, nil
		}
		p.events = p.eventbuf[0:nn]
	}
	ev := &p.events[0]
	p.events = p.events[1:]
	fd = int(ev.Ident)
	if ev.Filter == syscall.EVFILT_READ {
		mode = 'r'
	} else {
		mode = 'w'
	}
	return fd, mode, nil
}

func (p *pollster) Close() os.Error { return os.NewSyscallError("close", syscall.Close(p.kq)) }
<|endoftext|>


<commit_before>// Copyright 2010 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.

/*
	The netchan package implements type-safe networked channels:
	it allows the two ends of a channel to appear on different
	computers connected by a network.  It does this by transporting
	data sent to a channel on one machine so it can be recovered
	by a receive of a channel of the same type on the other.

	An exporter publishes a set of channels by name.  An importer
	connects to the exporting machine and imports the channels
	by name. After importing the channels, the two machines can
	use the channels in the usual way.

	Networked channels are not synchronized; they always behave
	as if they are buffered channels of at least one element.
*/
package netchan

// BUG: can't use range clause to receive when using ImportNValues to limit the count.

import (
	"log"
	"net"
	"os"
	"reflect"
	"sync"
)

// Export

// expLog is a logging convenience function.  The first argument must be a string.
func expLog(args ...interface{}) {
	args[0] = "netchan export: " + args[0].(string)
	log.Stderr(args...)
}

// An Exporter allows a set of channels to be published on a single
// network port.  A single machine may have multiple Exporters
// but they must use different ports.
type Exporter struct {
	*clientSet
	listener net.Listener
}

type expClient struct {
	*encDec
	exp     *Exporter
	mu      sync.Mutex // protects remaining fields
	errored bool       // client has been sent an error
	seqNum  int64      // sequences messages sent to client; has value of highest sent
	ackNum  int64      // highest sequence number acknowledged
}

func newClient(exp *Exporter, conn net.Conn) *expClient {
	client := new(expClient)
	client.exp = exp
	client.encDec = newEncDec(conn)
	client.seqNum = 0
	client.ackNum = 0
	return client

}

func (client *expClient) sendError(hdr *header, err string) {
	error := &error{err}
	expLog("sending error to client:", error.error)
	client.encode(hdr, payError, error) // ignore any encode error, hope client gets it
	client.mu.Lock()
	client.errored = true
	client.mu.Unlock()
}

func (client *expClient) getChan(hdr *header, dir Dir) *chanDir {
	exp := client.exp
	exp.mu.Lock()
	ech, ok := exp.chans[hdr.name]
	exp.mu.Unlock()
	if !ok {
		client.sendError(hdr, "no such channel: "+hdr.name)
		return nil
	}
	if ech.dir != dir {
		client.sendError(hdr, "wrong direction for channel: "+hdr.name)
		return nil
	}
	return ech
}

// The function run manages sends and receives for a single client.  For each
// (client Recv) request, this will launch a serveRecv goroutine to deliver
// the data for that channel, while (client Send) requests are handled as
// data arrives from the client.
func (client *expClient) run() {
	hdr := new(header)
	hdrValue := reflect.NewValue(hdr)
	req := new(request)
	reqValue := reflect.NewValue(req)
	error := new(error)
	for {
		*hdr = header{}
		if err := client.decode(hdrValue); err != nil {
			expLog("error decoding client header:", err)
			break
		}
		switch hdr.payloadType {
		case payRequest:
			if err := client.decode(reqValue); err != nil {
				expLog("error decoding client request:", err)
				break
			}
			switch req.dir {
			case Recv:
				go client.serveRecv(*hdr, req.count)
			case Send:
				// Request to send is clear as a matter of protocol
				// but not actually used by the implementation.
				// The actual sends will have payload type payData.
				// TODO: manage the count?
			default:
				error.error = "request: can't handle channel direction"
				expLog(error.error, req.dir)
				client.encode(hdr, payError, error)
			}
		case payData:
			client.serveSend(*hdr)
		case payClosed:
			client.serveClosed(*hdr)
		case payAck:
			client.mu.Lock()
			if client.ackNum != hdr.seqNum-1 {
				// Since the sequence number is incremented and the message is sent
				// in a single instance of locking client.mu, the messages are guaranteed
				// to be sent in order.  Therefore receipt of acknowledgement N means
				// all messages <=N have been seen by the recipient.  We check anyway.
				expLog("sequence out of order:", client.ackNum, hdr.seqNum)
			}
			if client.ackNum < hdr.seqNum { // If there has been an error, don't back up the count.
				client.ackNum = hdr.seqNum
			}
			client.mu.Unlock()
		default:
			log.Exit("netchan export: unknown payload type", hdr.payloadType)
		}
	}
	client.exp.delClient(client)
}

// Send all the data on a single channel to a client asking for a Recv.
// The header is passed by value to avoid issues of overwriting.
func (client *expClient) serveRecv(hdr header, count int64) {
	ech := client.getChan(&hdr, Send)
	if ech == nil {
		return
	}
	for {
		val := ech.ch.Recv()
		if ech.ch.Closed() {
			if err := client.encode(&hdr, payClosed, nil); err != nil {
				expLog("error encoding server closed message:", err)
			}
			break
		}
		// We hold the lock during transmission to guarantee messages are
		// sent in sequence number order.  Also, we increment first so the
		// value of client.seqNum is the value of the highest used sequence
		// number, not one beyond.
		client.mu.Lock()
		client.seqNum++
		hdr.seqNum = client.seqNum
		err := client.encode(&hdr, payData, val.Interface())
		client.mu.Unlock()
		if err != nil {
			expLog("error encoding client response:", err)
			client.sendError(&hdr, err.String())
			break
		}
		// Negative count means run forever.
		if count >= 0 {
			if count--; count <= 0 {
				break
			}
		}
	}
}

// Receive and deliver locally one item from a client asking for a Send
// The header is passed by value to avoid issues of overwriting.
func (client *expClient) serveSend(hdr header) {
	ech := client.getChan(&hdr, Recv)
	if ech == nil {
		return
	}
	// Create a new value for each received item.
	val := reflect.MakeZero(ech.ch.Type().(*reflect.ChanType).Elem())
	if err := client.decode(val); err != nil {
		expLog("value decode:", err)
		return
	}
	ech.ch.Send(val)
}

// Report that client has closed the channel that is sending to us.
// The header is passed by value to avoid issues of overwriting.
func (client *expClient) serveClosed(hdr header) {
	ech := client.getChan(&hdr, Recv)
	if ech == nil {
		return
	}
	ech.ch.Close()
}

func (client *expClient) unackedCount() int64 {
	client.mu.Lock()
	n := client.seqNum - client.ackNum
	client.mu.Unlock()
	return n
}

func (client *expClient) seq() int64 {
	client.mu.Lock()
	n := client.seqNum
	client.mu.Unlock()
	return n
}

func (client *expClient) ack() int64 {
	client.mu.Lock()
	n := client.seqNum
	client.mu.Unlock()
	return n
}

// Wait for incoming connections, start a new runner for each
func (exp *Exporter) listen() {
	for {
		conn, err := exp.listener.Accept()
		if err != nil {
			expLog("listen:", err)
			break
		}
		client := exp.addClient(conn)
		go client.run()
	}
}

// NewExporter creates a new Exporter to export channels
// on the network and local address defined as in net.Listen.
func NewExporter(network, localaddr string) (*Exporter, os.Error) {
	listener, err := net.Listen(network, localaddr)
	if err != nil {
		return nil, err
	}
	e := &Exporter{
		listener: listener,
		clientSet: &clientSet{
			chans:   make(map[string]*chanDir),
			clients: make(map[unackedCounter]bool),
		},
	}
	go e.listen()
	return e, nil
}

// addClient creates a new expClient and records its existence
func (exp *Exporter) addClient(conn net.Conn) *expClient {
	client := newClient(exp, conn)
	exp.clients[client] = true
	exp.mu.Unlock()
	return client
}

// delClient forgets the client existed
func (exp *Exporter) delClient(client *expClient) {
	exp.mu.Lock()
	exp.clients[client] = false, false
	exp.mu.Unlock()
}

// Drain waits until all messages sent from this exporter/importer, including
// those not yet sent to any client and possibly including those sent while
// Drain was executing, have been received by the importer.  In short, it
// waits until all the exporter's messages have been received by a client.
// If the timeout (measured in nanoseconds) is positive and Drain takes
// longer than that to complete, an error is returned.
func (exp *Exporter) Drain(timeout int64) os.Error {
	// This wrapper function is here so the method's comment will appear in godoc.
	return exp.clientSet.drain(timeout)
}

// Sync waits until all clients of the exporter have received the messages
// that were sent at the time Sync was invoked.  Unlike Drain, it does not
// wait for messages sent while it is running or messages that have not been
// dispatched to any client.  If the timeout (measured in nanoseconds) is
// positive and Sync takes longer than that to complete, an error is
// returned.
func (exp *Exporter) Sync(timeout int64) os.Error {
	// This wrapper function is here so the method's comment will appear in godoc.
	return exp.clientSet.sync(timeout)
}

// Addr returns the Exporter's local network address.
func (exp *Exporter) Addr() net.Addr { return exp.listener.Addr() }

func checkChan(chT interface{}, dir Dir) (*reflect.ChanValue, os.Error) {
	chanType, ok := reflect.Typeof(chT).(*reflect.ChanType)
	if !ok {
		return nil, os.ErrorString("not a channel")
	}
	if dir != Send && dir != Recv {
		return nil, os.ErrorString("unknown channel direction")
	}
	switch chanType.Dir() {
	case reflect.BothDir:
	case reflect.SendDir:
		if dir != Recv {
			return nil, os.ErrorString("to import/export with Send, must provide <-chan")
		}
	case reflect.RecvDir:
		if dir != Send {
			return nil, os.ErrorString("to import/export with Recv, must provide chan<-")
		}
	}
	return reflect.NewValue(chT).(*reflect.ChanValue), nil
}

// Export exports a channel of a given type and specified direction.  The
// channel to be exported is provided in the call and may be of arbitrary
// channel type.
// Despite the literal signature, the effective signature is
//	Export(name string, chT chan T, dir Dir)
func (exp *Exporter) Export(name string, chT interface{}, dir Dir) os.Error {
	ch, err := checkChan(chT, dir)
	if err != nil {
		return err
	}
	exp.mu.Lock()
	defer exp.mu.Unlock()
	_, present := exp.chans[name]
	if present {
		return os.ErrorString("channel name already being exported:" + name)
	}
	exp.chans[name] = &chanDir{ch, dir}
	return nil
}
<commit_msg>netchan: zero out request to ensure correct gob decoding. Gob decoding does not overwrite fields which are zero in the encoder. Fixes issue 1174.<commit_after>// Copyright 2010 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.

/*
	The netchan package implements type-safe networked channels:
	it allows the two ends of a channel to appear on different
	computers connected by a network.  It does this by transporting
	data sent to a channel on one machine so it can be recovered
	by a receive of a channel of the same type on the other.

	An exporter publishes a set of channels by name.  An importer
	connects to the exporting machine and imports the channels
	by name. After importing the channels, the two machines can
	use the channels in the usual way.

	Networked channels are not synchronized; they always behave
	as if they are buffered channels of at least one element.
*/
package netchan

// BUG: can't use range clause to receive when using ImportNValues to limit the count.

import (
	"log"
	"net"
	"os"
	"reflect"
	"sync"
)

// Export

// expLog is a logging convenience function.  The first argument must be a string.
func expLog(args ...interface{}) {
	args[0] = "netchan export: " + args[0].(string)
	log.Stderr(args...)
}

// An Exporter allows a set of channels to be published on a single
// network port.  A single machine may have multiple Exporters
// but they must use different ports.
type Exporter struct {
	*clientSet
	listener net.Listener
}

type expClient struct {
	*encDec
	exp     *Exporter
	mu      sync.Mutex // protects remaining fields
	errored bool       // client has been sent an error
	seqNum  int64      // sequences messages sent to client; has value of highest sent
	ackNum  int64      // highest sequence number acknowledged
}

func newClient(exp *Exporter, conn net.Conn) *expClient {
	client := new(expClient)
	client.exp = exp
	client.encDec = newEncDec(conn)
	client.seqNum = 0
	client.ackNum = 0
	return client

}

func (client *expClient) sendError(hdr *header, err string) {
	error := &error{err}
	expLog("sending error to client:", error.error)
	client.encode(hdr, payError, error) // ignore any encode error, hope client gets it
	client.mu.Lock()
	client.errored = true
	client.mu.Unlock()
}

func (client *expClient) getChan(hdr *header, dir Dir) *chanDir {
	exp := client.exp
	exp.mu.Lock()
	ech, ok := exp.chans[hdr.name]
	exp.mu.Unlock()
	if !ok {
		client.sendError(hdr, "no such channel: "+hdr.name)
		return nil
	}
	if ech.dir != dir {
		client.sendError(hdr, "wrong direction for channel: "+hdr.name)
		return nil
	}
	return ech
}

// The function run manages sends and receives for a single client.  For each
// (client Recv) request, this will launch a serveRecv goroutine to deliver
// the data for that channel, while (client Send) requests are handled as
// data arrives from the client.
func (client *expClient) run() {
	hdr := new(header)
	hdrValue := reflect.NewValue(hdr)
	req := new(request)
	reqValue := reflect.NewValue(req)
	error := new(error)
	for {
		*hdr = header{}
		if err := client.decode(hdrValue); err != nil {
			expLog("error decoding client header:", err)
			break
		}
		switch hdr.payloadType {
		case payRequest:
			*req = request{}
			if err := client.decode(reqValue); err != nil {
				expLog("error decoding client request:", err)
				break
			}
			switch req.dir {
			case Recv:
				go client.serveRecv(*hdr, req.count)
			case Send:
				// Request to send is clear as a matter of protocol
				// but not actually used by the implementation.
				// The actual sends will have payload type payData.
				// TODO: manage the count?
			default:
				error.error = "request: can't handle channel direction"
				expLog(error.error, req.dir)
				client.encode(hdr, payError, error)
			}
		case payData:
			client.serveSend(*hdr)
		case payClosed:
			client.serveClosed(*hdr)
		case payAck:
			client.mu.Lock()
			if client.ackNum != hdr.seqNum-1 {
				// Since the sequence number is incremented and the message is sent
				// in a single instance of locking client.mu, the messages are guaranteed
				// to be sent in order.  Therefore receipt of acknowledgement N means
				// all messages <=N have been seen by the recipient.  We check anyway.
				expLog("sequence out of order:", client.ackNum, hdr.seqNum)
			}
			if client.ackNum < hdr.seqNum { // If there has been an error, don't back up the count.
				client.ackNum = hdr.seqNum
			}
			client.mu.Unlock()
		default:
			log.Exit("netchan export: unknown payload type", hdr.payloadType)
		}
	}
	client.exp.delClient(client)
}

// Send all the data on a single channel to a client asking for a Recv.
// The header is passed by value to avoid issues of overwriting.
func (client *expClient) serveRecv(hdr header, count int64) {
	ech := client.getChan(&hdr, Send)
	if ech == nil {
		return
	}
	for {
		val := ech.ch.Recv()
		if ech.ch.Closed() {
			if err := client.encode(&hdr, payClosed, nil); err != nil {
				expLog("error encoding server closed message:", err)
			}
			break
		}
		// We hold the lock during transmission to guarantee messages are
		// sent in sequence number order.  Also, we increment first so the
		// value of client.seqNum is the value of the highest used sequence
		// number, not one beyond.
		client.mu.Lock()
		client.seqNum++
		hdr.seqNum = client.seqNum
		err := client.encode(&hdr, payData, val.Interface())
		client.mu.Unlock()
		if err != nil {
			expLog("error encoding client response:", err)
			client.sendError(&hdr, err.String())
			break
		}
		// Negative count means run forever.
		if count >= 0 {
			if count--; count <= 0 {
				break
			}
		}
	}
}

// Receive and deliver locally one item from a client asking for a Send
// The header is passed by value to avoid issues of overwriting.
func (client *expClient) serveSend(hdr header) {
	ech := client.getChan(&hdr, Recv)
	if ech == nil {
		return
	}
	// Create a new value for each received item.
	val := reflect.MakeZero(ech.ch.Type().(*reflect.ChanType).Elem())
	if err := client.decode(val); err != nil {
		expLog("value decode:", err)
		return
	}
	ech.ch.Send(val)
}

// Report that client has closed the channel that is sending to us.
// The header is passed by value to avoid issues of overwriting.
func (client *expClient) serveClosed(hdr header) {
	ech := client.getChan(&hdr, Recv)
	if ech == nil {
		return
	}
	ech.ch.Close()
}

func (client *expClient) unackedCount() int64 {
	client.mu.Lock()
	n := client.seqNum - client.ackNum
	client.mu.Unlock()
	return n
}

func (client *expClient) seq() int64 {
	client.mu.Lock()
	n := client.seqNum
	client.mu.Unlock()
	return n
}

func (client *expClient) ack() int64 {
	client.mu.Lock()
	n := client.seqNum
	client.mu.Unlock()
	return n
}

// Wait for incoming connections, start a new runner for each
func (exp *Exporter) listen() {
	for {
		conn, err := exp.listener.Accept()
		if err != nil {
			expLog("listen:", err)
			break
		}
		client := exp.addClient(conn)
		go client.run()
	}
}

// NewExporter creates a new Exporter to export channels
// on the network and local address defined as in net.Listen.
func NewExporter(network, localaddr string) (*Exporter, os.Error) {
	listener, err := net.Listen(network, localaddr)
	if err != nil {
		return nil, err
	}
	e := &Exporter{
		listener: listener,
		clientSet: &clientSet{
			chans:   make(map[string]*chanDir),
			clients: make(map[unackedCounter]bool),
		},
	}
	go e.listen()
	return e, nil
}

// addClient creates a new expClient and records its existence
func (exp *Exporter) addClient(conn net.Conn) *expClient {
	client := newClient(exp, conn)
	exp.clients[client] = true
	exp.mu.Unlock()
	return client
}

// delClient forgets the client existed
func (exp *Exporter) delClient(client *expClient) {
	exp.mu.Lock()
	exp.clients[client] = false, false
	exp.mu.Unlock()
}

// Drain waits until all messages sent from this exporter/importer, including
// those not yet sent to any client and possibly including those sent while
// Drain was executing, have been received by the importer.  In short, it
// waits until all the exporter's messages have been received by a client.
// If the timeout (measured in nanoseconds) is positive and Drain takes
// longer than that to complete, an error is returned.
func (exp *Exporter) Drain(timeout int64) os.Error {
	// This wrapper function is here so the method's comment will appear in godoc.
	return exp.clientSet.drain(timeout)
}

// Sync waits until all clients of the exporter have received the messages
// that were sent at the time Sync was invoked.  Unlike Drain, it does not
// wait for messages sent while it is running or messages that have not been
// dispatched to any client.  If the timeout (measured in nanoseconds) is
// positive and Sync takes longer than that to complete, an error is
// returned.
func (exp *Exporter) Sync(timeout int64) os.Error {
	// This wrapper function is here so the method's comment will appear in godoc.
	return exp.clientSet.sync(timeout)
}

// Addr returns the Exporter's local network address.
func (exp *Exporter) Addr() net.Addr { return exp.listener.Addr() }

func checkChan(chT interface{}, dir Dir) (*reflect.ChanValue, os.Error) {
	chanType, ok := reflect.Typeof(chT).(*reflect.ChanType)
	if !ok {
		return nil, os.ErrorString("not a channel")
	}
	if dir != Send && dir != Recv {
		return nil, os.ErrorString("unknown channel direction")
	}
	switch chanType.Dir() {
	case reflect.BothDir:
	case reflect.SendDir:
		if dir != Recv {
			return nil, os.ErrorString("to import/export with Send, must provide <-chan")
		}
	case reflect.RecvDir:
		if dir != Send {
			return nil, os.ErrorString("to import/export with Recv, must provide chan<-")
		}
	}
	return reflect.NewValue(chT).(*reflect.ChanValue), nil
}

// Export exports a channel of a given type and specified direction.  The
// channel to be exported is provided in the call and may be of arbitrary
// channel type.
// Despite the literal signature, the effective signature is
//	Export(name string, chT chan T, dir Dir)
func (exp *Exporter) Export(name string, chT interface{}, dir Dir) os.Error {
	ch, err := checkChan(chT, dir)
	if err != nil {
		return err
	}
	exp.mu.Lock()
	defer exp.mu.Unlock()
	_, present := exp.chans[name]
	if present {
		return os.ErrorString("channel name already being exported:" + name)
	}
	exp.chans[name] = &chanDir{ch, dir}
	return nil
}
<|endoftext|>


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

/*
	Package runtime contains operations that interact with Go's runtime system,
	such as functions to control goroutines. It also includes the low-level type information
	used by the reflect package; see reflect's documentation for the programmable
	interface to the run-time type system.
*/
package runtime

// Gosched yields the processor, allowing other goroutines to run.  It does not
// suspend the current goroutine, so execution resumes automatically.
func Gosched()

// Goexit terminates the goroutine that calls it.  No other goroutine is affected.
// Goexit runs all deferred calls before terminating the goroutine.
func Goexit()

// Caller reports file and line number information about function invocations on
// the calling goroutine's stack.  The argument skip is the number of stack frames to
// ascend, with 0 identifying the the caller of Caller.  The return values report the
// program counter, file name, and line number within the file of the corresponding
// call.  The boolean ok is false if it was not possible to recover the information.
func Caller(skip int) (pc uintptr, file string, line int, ok bool)

// Callers fills the slice pc with the program counters of function invocations
// on the calling goroutine's stack.  The argument skip is the number of stack frames
// to skip before recording in pc, with 0 starting at the caller of Caller.
// It returns the number of entries written to pc.
func Callers(skip int, pc []uintptr) int

type Func struct { // Keep in sync with runtime.h:struct Func
	name   string
	typ    string  // go type string
	src    string  // src file name
	pcln   []byte  // pc/ln tab for this func
	entry  uintptr // entry pc
	pc0    uintptr // starting pc, ln for table
	ln0    int32
	frame  int32 // stack frame size
	args   int32 // number of 32-bit in/out args
	locals int32 // number of 32-bit locals
}

// FuncForPC returns a *Func describing the function that contains the
// given program counter address, or else nil.
func FuncForPC(pc uintptr) *Func

// Name returns the name of the function.
func (f *Func) Name() string { return f.name }

// Entry returns the entry address of the function.
func (f *Func) Entry() uintptr { return f.entry }

// FileLine returns the file name and line number of the
// source code corresponding to the program counter pc.
// The result will not be accurate if pc is not a program
// counter within f.
func (f *Func) FileLine(pc uintptr) (file string, line int) {
	// NOTE(rsc): If you edit this function, also edit
	// symtab.c:/^funcline.  That function also has the
	// comments explaining the logic.
	targetpc := pc

	var pcQuant uintptr = 1
	if GOARCH == "arm" {
		pcQuant = 4
	}

	p := f.pcln
	pc = f.pc0
	line = int(f.ln0)
	i := 0
	//print("FileLine start pc=", pc, " targetpc=", targetpc, " line=", line,
	//	" tab=", p, " ", p[0], " quant=", pcQuant, " GOARCH=", GOARCH, "\n")
	for {
		for i < len(p) && p[i] > 128 {
			pc += pcQuant * uintptr(p[i]-128)
			i++
		}
		//print("pc<", pc, " targetpc=", targetpc, " line=", line, "\n")
		if pc > targetpc || i >= len(p) {
			break
		}
		if p[i] == 0 {
			if i+5 > len(p) {
				break
			}
			line += int(p[i+1]<<24) | int(p[i+2]<<16) | int(p[i+3]<<8) | int(p[i+4])
			i += 5
		} else if p[i] <= 64 {
			line += int(p[i])
			i++
		} else {
			line -= int(p[i] - 64)
			i++
		}
		//print("pc=", pc, " targetpc=", targetpc, " line=", line, "\n")
		pc += pcQuant
	}
	file = f.src
	return
}

// mid returns the current os thread (m) id.
func mid() uint32

// Semacquire waits until *s > 0 and then atomically decrements it.
// It is intended as a simple sleep primitive for use by the synchronization
// library and should not be used directly.
func Semacquire(s *uint32)

// Semrelease atomically increments *s and notifies a waiting goroutine
// if one is blocked in Semacquire.
// It is intended as a simple wakeup primitive for use by the synchronization
// library and should not be used directly.
func Semrelease(s *uint32)

// SetFinalizer sets the finalizer associated with x to f.
// When the garbage collector finds an unreachable block
// with an associated finalizer, it clears the association and runs
// f(x) in a separate goroutine.  This makes x reachable again, but
// now without an associated finalizer.  Assuming that SetFinalizer
// is not called again, the next time the garbage collector sees
// that x is unreachable, it will free x.
//
// SetFinalizer(x, nil) clears any finalizer associated with x.
//
// The argument x must be a pointer to an object allocated by
// calling new or by taking the address of a composite literal.
// The argument f must be a function that takes a single argument
// of x's type and can have arbitrary ignored return values.
// If either of these is not true, SetFinalizer aborts the program.
//
// Finalizers are run in dependency order: if A points at B, both have
// finalizers, and they are otherwise unreachable, only the finalizer
// for A runs; once A is freed, the finalizer for B can run.
// If a cyclic structure includes a block with a finalizer, that
// cycle is not guaranteed to be garbage collected and the finalizer
// is not guaranteed to run, because there is no ordering that
// respects the dependencies.
//
// The finalizer for x is scheduled to run at some arbitrary time after
// x becomes unreachable.
// There is no guarantee that finalizers will run before a program exits,
// so typically they are useful only for releasing non-memory resources
// associated with an object during a long-running program.
// For example, an os.File object could use a finalizer to close the
// associated operating system file descriptor when a program discards
// an os.File without calling Close, but it would be a mistake
// to depend on a finalizer to flush an in-memory I/O buffer such as a
// bufio.Writer, because the buffer would not be flushed at program exit.
//
// A single goroutine runs all finalizers for a program, sequentially.
// If a finalizer must run for a long time, it should do so by starting
// a new goroutine.
func SetFinalizer(x, f interface{})

func getgoroot() string

// GOROOT returns the root of the Go tree.
// It uses the GOROOT environment variable, if set,
// or else the root used during the Go build.
func GOROOT() string {
	s := getgoroot()
	if s != "" {
		return s
	}
	return defaultGoroot
}

// Version returns the Go tree's version string.
// It is either a sequence number or, when possible,
// a release tag like "release.2010-03-04".
// A trailing + indicates that the tree had local modifications
// at the time of the build.
func Version() string {
	return theVersion
}

// GOOS is the Go tree's operating system target:
// one of darwin, freebsd, linux, and so on.
const GOOS string = theGoos

// GOARCH is the Go tree's architecture target:
// 386, amd64, or arm.
const GOARCH string = theGoarch
<commit_msg>runtime: fix typo in comment<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/*
	Package runtime contains operations that interact with Go's runtime system,
	such as functions to control goroutines. It also includes the low-level type information
	used by the reflect package; see reflect's documentation for the programmable
	interface to the run-time type system.
*/
package runtime

// Gosched yields the processor, allowing other goroutines to run.  It does not
// suspend the current goroutine, so execution resumes automatically.
func Gosched()

// Goexit terminates the goroutine that calls it.  No other goroutine is affected.
// Goexit runs all deferred calls before terminating the goroutine.
func Goexit()

// Caller reports file and line number information about function invocations on
// the calling goroutine's stack.  The argument skip is the number of stack frames
// to ascend, with 0 identifying the caller of Caller.  The return values report the
// program counter, file name, and line number within the file of the corresponding
// call.  The boolean ok is false if it was not possible to recover the information.
func Caller(skip int) (pc uintptr, file string, line int, ok bool)

// Callers fills the slice pc with the program counters of function invocations
// on the calling goroutine's stack.  The argument skip is the number of stack frames
// to skip before recording in pc, with 0 starting at the caller of Caller.
// It returns the number of entries written to pc.
func Callers(skip int, pc []uintptr) int

type Func struct { // Keep in sync with runtime.h:struct Func
	name   string
	typ    string  // go type string
	src    string  // src file name
	pcln   []byte  // pc/ln tab for this func
	entry  uintptr // entry pc
	pc0    uintptr // starting pc, ln for table
	ln0    int32
	frame  int32 // stack frame size
	args   int32 // number of 32-bit in/out args
	locals int32 // number of 32-bit locals
}

// FuncForPC returns a *Func describing the function that contains the
// given program counter address, or else nil.
func FuncForPC(pc uintptr) *Func

// Name returns the name of the function.
func (f *Func) Name() string { return f.name }

// Entry returns the entry address of the function.
func (f *Func) Entry() uintptr { return f.entry }

// FileLine returns the file name and line number of the
// source code corresponding to the program counter pc.
// The result will not be accurate if pc is not a program
// counter within f.
func (f *Func) FileLine(pc uintptr) (file string, line int) {
	// NOTE(rsc): If you edit this function, also edit
	// symtab.c:/^funcline.  That function also has the
	// comments explaining the logic.
	targetpc := pc

	var pcQuant uintptr = 1
	if GOARCH == "arm" {
		pcQuant = 4
	}

	p := f.pcln
	pc = f.pc0
	line = int(f.ln0)
	i := 0
	//print("FileLine start pc=", pc, " targetpc=", targetpc, " line=", line,
	//	" tab=", p, " ", p[0], " quant=", pcQuant, " GOARCH=", GOARCH, "\n")
	for {
		for i < len(p) && p[i] > 128 {
			pc += pcQuant * uintptr(p[i]-128)
			i++
		}
		//print("pc<", pc, " targetpc=", targetpc, " line=", line, "\n")
		if pc > targetpc || i >= len(p) {
			break
		}
		if p[i] == 0 {
			if i+5 > len(p) {
				break
			}
			line += int(p[i+1]<<24) | int(p[i+2]<<16) | int(p[i+3]<<8) | int(p[i+4])
			i += 5
		} else if p[i] <= 64 {
			line += int(p[i])
			i++
		} else {
			line -= int(p[i] - 64)
			i++
		}
		//print("pc=", pc, " targetpc=", targetpc, " line=", line, "\n")
		pc += pcQuant
	}
	file = f.src
	return
}

// mid returns the current os thread (m) id.
func mid() uint32

// Semacquire waits until *s > 0 and then atomically decrements it.
// It is intended as a simple sleep primitive for use by the synchronization
// library and should not be used directly.
func Semacquire(s *uint32)

// Semrelease atomically increments *s and notifies a waiting goroutine
// if one is blocked in Semacquire.
// It is intended as a simple wakeup primitive for use by the synchronization
// library and should not be used directly.
func Semrelease(s *uint32)

// SetFinalizer sets the finalizer associated with x to f.
// When the garbage collector finds an unreachable block
// with an associated finalizer, it clears the association and runs
// f(x) in a separate goroutine.  This makes x reachable again, but
// now without an associated finalizer.  Assuming that SetFinalizer
// is not called again, the next time the garbage collector sees
// that x is unreachable, it will free x.
//
// SetFinalizer(x, nil) clears any finalizer associated with x.
//
// The argument x must be a pointer to an object allocated by
// calling new or by taking the address of a composite literal.
// The argument f must be a function that takes a single argument
// of x's type and can have arbitrary ignored return values.
// If either of these is not true, SetFinalizer aborts the program.
//
// Finalizers are run in dependency order: if A points at B, both have
// finalizers, and they are otherwise unreachable, only the finalizer
// for A runs; once A is freed, the finalizer for B can run.
// If a cyclic structure includes a block with a finalizer, that
// cycle is not guaranteed to be garbage collected and the finalizer
// is not guaranteed to run, because there is no ordering that
// respects the dependencies.
//
// The finalizer for x is scheduled to run at some arbitrary time after
// x becomes unreachable.
// There is no guarantee that finalizers will run before a program exits,
// so typically they are useful only for releasing non-memory resources
// associated with an object during a long-running program.
// For example, an os.File object could use a finalizer to close the
// associated operating system file descriptor when a program discards
// an os.File without calling Close, but it would be a mistake
// to depend on a finalizer to flush an in-memory I/O buffer such as a
// bufio.Writer, because the buffer would not be flushed at program exit.
//
// A single goroutine runs all finalizers for a program, sequentially.
// If a finalizer must run for a long time, it should do so by starting
// a new goroutine.
func SetFinalizer(x, f interface{})

func getgoroot() string

// GOROOT returns the root of the Go tree.
// It uses the GOROOT environment variable, if set,
// or else the root used during the Go build.
func GOROOT() string {
	s := getgoroot()
	if s != "" {
		return s
	}
	return defaultGoroot
}

// Version returns the Go tree's version string.
// It is either a sequence number or, when possible,
// a release tag like "release.2010-03-04".
// A trailing + indicates that the tree had local modifications
// at the time of the build.
func Version() string {
	return theVersion
}

// GOOS is the Go tree's operating system target:
// one of darwin, freebsd, linux, and so on.
const GOOS string = theGoos

// GOARCH is the Go tree's architecture target:
// 386, amd64, or arm.
const GOARCH string = theGoarch
<|endoftext|>


<commit_before>// Package gokeepasslib is a library written in go which provides functionality to decrypt and parse keepass 2 files (kdbx)
package gokeepasslib

import (
	"encoding/xml"
	"encoding/base64"
	"time"
	"crypto/rand"
)

// DBContent is a container for all elements of a keepass database
type DBContent struct {
	XMLName xml.Name  `xml:"KeePassFile"`
	Meta    *MetaData `xml:"Meta"`
	Root    *RootData `xml:"Root"`
}

// NewDBContent creates a new DB content with some good defaults
func NewDBContent() *DBContent {
	content := new(DBContent)
	content.Meta = NewMetaData()
	content.Root = NewRootData()
	return content
}

// MetaData is the structure for the metadata headers at the top of kdbx files,
// it contains things like the name of the database
type MetaData struct {
	Generator                  string        `xml:"Generator"`
	HeaderHash                 string        `xml:"HeaderHash"`
	DatabaseName               string        `xml:"DatabaseName"`
	DatabaseNameChanged        *time.Time    `xml:"DatabaseNameChanged"`
	DatabaseDescription        string        `xml:"DatabaseDescription"`
	DatabaseDescriptionChanged *time.Time    `xml:"DatabaseDescriptionChanged"`
	DefaultUserName            string        `xml:"DefaultUserName"`
	DefaultUserNameChanged     *time.Time    `xml:"DefaultUserNameChanged"`
	MaintenanceHistoryDays     string        `xml:"MaintenanceHistoryDays"`
	Color                      string        `xml:"Color"`
	MasterKeyChanged           *time.Time    `xml:"MasterKeyChanged"`
	MasterKeyChangeRec         int64         `xml:"MasterKeyChangeRec"`
	MasterKeyChangeForce       int64         `xml:"MasterKeyChangeForce"`
	MemoryProtection           MemProtection `xml:"MemoryProtection"`
	RecycleBinEnabled          boolWrapper   `xml:"RecycleBinEnabled"`
	RecycleBinUUID             UUID        `xml:"RecycleBinUUID"`
	RecycleBinChanged          *time.Time    `xml:"RecycleBinChanged"`
	EntryTemplatesGroup        string        `xml:"EntryTemplatesGroup"`
	EntryTemplatesGroupChanged *time.Time    `xml:"EntryTemplatesGroupChanged"`
	HistoryMaxItems            int64         `xml:"HistoryMaxItems"`
	HistoryMaxSize             int64         `xml:"HistoryMaxSize"`
	LastSelectedGroup          string        `xml:"LastSelectedGroup"`
	LastTopVisibleGroup        string        `xml:"LastTopVisibleGroup"`
	Binaries                   Binaries      `xml:"Binaries>Binary"`
	CustomData                 string        `xml:"CustomData"`
}

// NewMetaData creates a MetaData struct with some defaults set
func NewMetaData() *MetaData {
	meta := new(MetaData)
	now := time.Now()
	meta.MasterKeyChanged = &now
	meta.MasterKeyChangeRec = -1
	meta.MasterKeyChangeForce = -1
	return meta
}

// MemProtection is a structure containing settings for MemoryProtection
type MemProtection struct {
	ProtectTitle    boolWrapper `xml:"ProtectTitle"`
	ProtectUserName boolWrapper `xml:"ProtectUserName"`
	ProtectPassword boolWrapper `xml:"ProtectPassword"`
	ProtectURL      boolWrapper `xml:"ProtectURL"`
	ProtectNotes    boolWrapper `xml:"ProtectNotes"`
}

// RootData stores the actual content of a database (all enteries sorted into groups and the recycle bin)
type RootData struct {
	Groups         []Group             `xml:"Group"`
	DeletedObjects []DeletedObjectData `xml:"DeletedObjects>DeletedObject"`
}

// NewRootData returns a RootData struct with good defaults
func NewRootData() *RootData {
	root := new(RootData)
	group := NewGroup()
	group.Name = "NewDatabase"
	entry := NewEntry()
	entry.Values = append(entry.Values, ValueData{Key: "Title", Value: V{Content: "Sample Entry"}})
	group.Entries = append(group.Entries, entry)
	root.Groups = append(root.Groups, group)
	return root
}

// UUID stores a universal identifier for each group+entry
type UUID [16]byte

// NewUUID returns a new randomly generated UUID
func NewUUID () UUID {
	var id UUID
	rand.Read(id[:])
	return id
}

func (u UUID) MarshalText () (text []byte, err error) {
	str := base64.StdEncoding.EncodeToString(u[:])
	return []byte(str),nil
}

func (u *UUID) UnmarshalText(text []byte) error {
	id,err := base64.StdEncoding.DecodeString(string(text))
	if err != nil {
		return err
	}
	copy((*u)[:],id[:16])
	return nil
}

//Compares check if c and u are equal, used for searching for a uuid
func (u UUID) Compare (c UUID) bool {
	for i,v := range c {
		if u[i] != v {
			return false
		}
	}
	return true
}

// Group is a structure to store entries in their named groups for organization
type Group struct {
	UUID                    UUID        `xml:"UUID"`
	Name                    string      `xml:"Name"`
	Notes                   string      `xml:"Notes"`
	IconID                  int64       `xml:"IconID"`
	Times                   TimeData    `xml:"Times"`
	IsExpanded              boolWrapper `xml:"IsExpanded"`
	DefaultAutoTypeSequence string      `xml:"DefaultAutoTypeSequence"`
	EnableAutoType          string      `xml:"EnableAutoType"`
	EnableSearching         string      `xml:"EnableSearching"`
	LastTopVisibleEntry     string      `xml:"LastTopVisibleEntry"`
	Groups                  []Group     `xml:"Group,omitempty"`
	Entries                 []Entry     `xml:"Entry,omitempty"`
}

//NewGroup returns a new group with time data and uuid set
func NewGroup () Group {
	g := Group{}
	g.Times = NewTimeData()
	g.UUID = NewUUID()
	return g
}

// TimeData contains all metadata related to times for groups and entries
// e.g. the last modification time or the creation time
type TimeData struct {
	CreationTime         *time.Time  `xml:"CreationTime"`
	LastModificationTime *time.Time  `xml:"LastModificationTime"`
	LastAccessTime       *time.Time  `xml:"LastAccessTime"`
	ExpiryTime           *time.Time  `xml:"ExpiryTime"`
	Expires              boolWrapper `xml:"Expires"`
	UsageCount           int64       `xml:"UsageCount"`
	LocationChanged      *time.Time  `xml:"LocationChanged"`
}

// NewTimeData returns a TimeData struct with good defaults (no expire time, all times set to now)
func NewTimeData() TimeData {
	now := time.Now()
	return TimeData{
		CreationTime:         &now,
		LastModificationTime: &now,
		LastAccessTime:       &now,
		LocationChanged:      &now,
		Expires:              false,
		UsageCount:           0,
	}
}

// Entry is the structure which holds information about a parsed entry in a keepass database
type Entry struct {
	UUID            UUID              `xml:"UUID"`
	IconID          int64             `xml:"IconID"`
	ForegroundColor string            `xml:"ForegroundColor"`
	BackgroundColor string            `xml:"BackgroundColor"`
	OverrideURL     string            `xml:"OverrideURL"`
	Tags            string            `xml:"Tags"`
	Times           TimeData          `xml:"Times"`
	Values          []ValueData       `xml:"String,omitempty"`
	AutoType        AutoTypeData      `xml:"AutoType"`
	Histories       []History         `xml:"History"`
	Password        []byte            `xml:"-"`
	Binaries        []BinaryReference `xml:"Binary,omitempty"`
}

// NewEntry return a new entry with time data and uuid set
func NewEntry () Entry {
	e := Entry{}
	e.Times = NewTimeData()
	e.UUID = NewUUID()
	return e
}

// Returns true if the e's password has in-memory protection
func (e *Entry) protected() bool {
	for _, v := range e.Values {
		if v.Key == "Password" && bool(v.Value.Protected) {
			return true
		}
	}
	return false
}

// Get returns the value in e corresponding with key k, or an empty string otherwise
func (e *Entry) Get(key string) *ValueData {
	for i, _ := range e.Values {
		if e.Values[i].Key == key {
			return &e.Values[i]
		}
	}
	return nil
}

// GetContent returns the content of the value belonging to the given key in string form
func (e *Entry) GetContent(key string) string {
	val := e.Get(key)
	if val == nil {
		return ""
	}
	return val.Value.Content
}

// GetIndex returns the index of the Value belonging to the given key, or -1 if none is found
func (e *Entry) GetIndex(key string) int {
	for i, _ := range e.Values {
		if e.Values[i].Key == key {
			return i
		}
	}
	return -1
}

// GetPassword returns the password of an entry
func (e *Entry) GetPassword() string {
	return e.GetContent("Password")
}

// GetPasswordIndex returns the index in the values slice belonging to the password
func (e *Entry) GetPasswordIndex() int {
	return e.GetIndex("Password")
}

// GetTitle returns the title of an entry
func (e *Entry) GetTitle() string {
	return e.GetContent("Title")
}

// History stores information about changes made to an entry,
// in the form of a list of previous versions of that entry
type History struct {
	Entries []Entry `xml:"Entry"`
}

// ValueData is a structure containing key value pairs of information stored in an entry
type ValueData struct {
	Key   string `xml:"Key"`
	Value V      `xml:"Value"`
}

// V is a wrapper for the content of a value, so that it can store whether it is protected
type V struct {
	Content   string      `xml:",innerxml"`
	Protected boolWrapper `xml:"Protected,attr,omitempty"`
}

type AutoTypeData struct {
	Enabled                 boolWrapper         `xml:"Enabled"`
	DataTransferObfuscation int64               `xml:"DataTransferObfuscation"`
	Association             AutoTypeAssociation `xml:"Association"`
}

type AutoTypeAssociation struct {
	Window            string `xml:"Window"`
	KeystrokeSequence string `xml:"KeystrokeSequence"`
}

type DeletedObjectData struct {
	XMLName      xml.Name   `xml:"DeletedObject"`
	UUID         UUID     `xml:"UUID"`
	DeletionTime *time.Time `xml:"DeletionTime"`
}
<commit_msg>fixed indention<commit_after>// Package gokeepasslib is a library written in go which provides functionality to decrypt and parse keepass 2 files (kdbx)
package gokeepasslib

import (
	"encoding/xml"
	"encoding/base64"
	"time"
	"crypto/rand"
)

// DBContent is a container for all elements of a keepass database
type DBContent struct {
	XMLName xml.Name  `xml:"KeePassFile"`
	Meta    *MetaData `xml:"Meta"`
	Root    *RootData `xml:"Root"`
}

// NewDBContent creates a new DB content with some good defaults
func NewDBContent() *DBContent {
	content := new(DBContent)
	content.Meta = NewMetaData()
	content.Root = NewRootData()
	return content
}

// MetaData is the structure for the metadata headers at the top of kdbx files,
// it contains things like the name of the database
type MetaData struct {
	Generator                  string        `xml:"Generator"`
	HeaderHash                 string        `xml:"HeaderHash"`
	DatabaseName               string        `xml:"DatabaseName"`
	DatabaseNameChanged        *time.Time    `xml:"DatabaseNameChanged"`
	DatabaseDescription        string        `xml:"DatabaseDescription"`
	DatabaseDescriptionChanged *time.Time    `xml:"DatabaseDescriptionChanged"`
	DefaultUserName            string        `xml:"DefaultUserName"`
	DefaultUserNameChanged     *time.Time    `xml:"DefaultUserNameChanged"`
	MaintenanceHistoryDays     string        `xml:"MaintenanceHistoryDays"`
	Color                      string        `xml:"Color"`
	MasterKeyChanged           *time.Time    `xml:"MasterKeyChanged"`
	MasterKeyChangeRec         int64         `xml:"MasterKeyChangeRec"`
	MasterKeyChangeForce       int64         `xml:"MasterKeyChangeForce"`
	MemoryProtection           MemProtection `xml:"MemoryProtection"`
	RecycleBinEnabled          boolWrapper   `xml:"RecycleBinEnabled"`
	RecycleBinUUID             UUID          `xml:"RecycleBinUUID"`
	RecycleBinChanged          *time.Time    `xml:"RecycleBinChanged"`
	EntryTemplatesGroup        string        `xml:"EntryTemplatesGroup"`
	EntryTemplatesGroupChanged *time.Time    `xml:"EntryTemplatesGroupChanged"`
	HistoryMaxItems            int64         `xml:"HistoryMaxItems"`
	HistoryMaxSize             int64         `xml:"HistoryMaxSize"`
	LastSelectedGroup          string        `xml:"LastSelectedGroup"`
	LastTopVisibleGroup        string        `xml:"LastTopVisibleGroup"`
	Binaries                   Binaries      `xml:"Binaries>Binary"`
	CustomData                 string        `xml:"CustomData"`
}

// NewMetaData creates a MetaData struct with some defaults set
func NewMetaData() *MetaData {
	meta := new(MetaData)
	now := time.Now()
	meta.MasterKeyChanged = &now
	meta.MasterKeyChangeRec = -1
	meta.MasterKeyChangeForce = -1
	return meta
}

// MemProtection is a structure containing settings for MemoryProtection
type MemProtection struct {
	ProtectTitle    boolWrapper `xml:"ProtectTitle"`
	ProtectUserName boolWrapper `xml:"ProtectUserName"`
	ProtectPassword boolWrapper `xml:"ProtectPassword"`
	ProtectURL      boolWrapper `xml:"ProtectURL"`
	ProtectNotes    boolWrapper `xml:"ProtectNotes"`
}

// RootData stores the actual content of a database (all enteries sorted into groups and the recycle bin)
type RootData struct {
	Groups         []Group             `xml:"Group"`
	DeletedObjects []DeletedObjectData `xml:"DeletedObjects>DeletedObject"`
}

// NewRootData returns a RootData struct with good defaults
func NewRootData() *RootData {
	root := new(RootData)
	group := NewGroup()
	group.Name = "NewDatabase"
	entry := NewEntry()
	entry.Values = append(entry.Values, ValueData{Key: "Title", Value: V{Content: "Sample Entry"}})
	group.Entries = append(group.Entries, entry)
	root.Groups = append(root.Groups, group)
	return root
}

// UUID stores a universal identifier for each group+entry
type UUID [16]byte

// NewUUID returns a new randomly generated UUID
func NewUUID () UUID {
	var id UUID
	rand.Read(id[:])
	return id
}

func (u UUID) MarshalText () ([]byte,error) {
	str := base64.StdEncoding.EncodeToString(u[:])
	return []byte(str),nil
}

func (u *UUID) UnmarshalText(text []byte) error {
	id,err := base64.StdEncoding.DecodeString(string(text))
	if err != nil {
		return err
	}
	copy((*u)[:],id[:16])
	return nil
}

//Compares check if c and u are equal, used for searching for a uuid
func (u UUID) Compare (c UUID) bool {
	for i,v := range c {
		if u[i] != v {
			return false
		}
	}
	return true
}

// Group is a structure to store entries in their named groups for organization
type Group struct {
	UUID                    UUID        `xml:"UUID"`
	Name                    string      `xml:"Name"`
	Notes                   string      `xml:"Notes"`
	IconID                  int64       `xml:"IconID"`
	Times                   TimeData    `xml:"Times"`
	IsExpanded              boolWrapper `xml:"IsExpanded"`
	DefaultAutoTypeSequence string      `xml:"DefaultAutoTypeSequence"`
	EnableAutoType          string      `xml:"EnableAutoType"`
	EnableSearching         string      `xml:"EnableSearching"`
	LastTopVisibleEntry     string      `xml:"LastTopVisibleEntry"`
	Groups                  []Group     `xml:"Group,omitempty"`
	Entries                 []Entry     `xml:"Entry,omitempty"`
}

//NewGroup returns a new group with time data and uuid set
func NewGroup () Group {
	g := Group{}
	g.Times = NewTimeData()
	g.UUID = NewUUID()
	return g
}

// TimeData contains all metadata related to times for groups and entries
// e.g. the last modification time or the creation time
type TimeData struct {
	CreationTime         *time.Time  `xml:"CreationTime"`
	LastModificationTime *time.Time  `xml:"LastModificationTime"`
	LastAccessTime       *time.Time  `xml:"LastAccessTime"`
	ExpiryTime           *time.Time  `xml:"ExpiryTime"`
	Expires              boolWrapper `xml:"Expires"`
	UsageCount           int64       `xml:"UsageCount"`
	LocationChanged      *time.Time  `xml:"LocationChanged"`
}

// NewTimeData returns a TimeData struct with good defaults (no expire time, all times set to now)
func NewTimeData() TimeData {
	now := time.Now()
	return TimeData{
		CreationTime:         &now,
		LastModificationTime: &now,
		LastAccessTime:       &now,
		LocationChanged:      &now,
		Expires:              false,
		UsageCount:           0,
	}
}

// Entry is the structure which holds information about a parsed entry in a keepass database
type Entry struct {
	UUID            UUID              `xml:"UUID"`
	IconID          int64             `xml:"IconID"`
	ForegroundColor string            `xml:"ForegroundColor"`
	BackgroundColor string            `xml:"BackgroundColor"`
	OverrideURL     string            `xml:"OverrideURL"`
	Tags            string            `xml:"Tags"`
	Times           TimeData          `xml:"Times"`
	Values          []ValueData       `xml:"String,omitempty"`
	AutoType        AutoTypeData      `xml:"AutoType"`
	Histories       []History         `xml:"History"`
	Password        []byte            `xml:"-"`
	Binaries        []BinaryReference `xml:"Binary,omitempty"`
}

// NewEntry return a new entry with time data and uuid set
func NewEntry () Entry {
	e := Entry{}
	e.Times = NewTimeData()
	e.UUID = NewUUID()
	return e
}

// Returns true if the e's password has in-memory protection
func (e *Entry) protected() bool {
	for _, v := range e.Values {
		if v.Key == "Password" && bool(v.Value.Protected) {
			return true
		}
	}
	return false
}

// Get returns the value in e corresponding with key k, or an empty string otherwise
func (e *Entry) Get(key string) *ValueData {
	for i, _ := range e.Values {
		if e.Values[i].Key == key {
			return &e.Values[i]
		}
	}
	return nil
}

// GetContent returns the content of the value belonging to the given key in string form
func (e *Entry) GetContent(key string) string {
	val := e.Get(key)
	if val == nil {
		return ""
	}
	return val.Value.Content
}

// GetIndex returns the index of the Value belonging to the given key, or -1 if none is found
func (e *Entry) GetIndex(key string) int {
	for i, _ := range e.Values {
		if e.Values[i].Key == key {
			return i
		}
	}
	return -1
}

// GetPassword returns the password of an entry
func (e *Entry) GetPassword() string {
	return e.GetContent("Password")
}

// GetPasswordIndex returns the index in the values slice belonging to the password
func (e *Entry) GetPasswordIndex() int {
	return e.GetIndex("Password")
}

// GetTitle returns the title of an entry
func (e *Entry) GetTitle() string {
	return e.GetContent("Title")
}

// History stores information about changes made to an entry,
// in the form of a list of previous versions of that entry
type History struct {
	Entries []Entry `xml:"Entry"`
}

// ValueData is a structure containing key value pairs of information stored in an entry
type ValueData struct {
	Key   string `xml:"Key"`
	Value V      `xml:"Value"`
}

// V is a wrapper for the content of a value, so that it can store whether it is protected
type V struct {
	Content   string      `xml:",innerxml"`
	Protected boolWrapper `xml:"Protected,attr,omitempty"`
}

type AutoTypeData struct {
	Enabled                 boolWrapper         `xml:"Enabled"`
	DataTransferObfuscation int64               `xml:"DataTransferObfuscation"`
	Association             AutoTypeAssociation `xml:"Association"`
}

type AutoTypeAssociation struct {
	Window            string `xml:"Window"`
	KeystrokeSequence string `xml:"KeystrokeSequence"`
}

type DeletedObjectData struct {
	XMLName      xml.Name   `xml:"DeletedObject"`
	UUID         UUID     `xml:"UUID"`
	DeletionTime *time.Time `xml:"DeletionTime"`
}
<|endoftext|>


<commit_before>package dotweb

import (
	"encoding/json"
	"errors"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"

	"github.com/devfeel/dotweb/router"
	"github.com/devfeel/dotweb/session"
	"github.com/labstack/echo"
)

const (
	defaultMemory = 32 << 20 // 32 MB
)

type HttpContext struct {
	Request      *http.Request
	RouterParams router.Params
	Response     *Response
	WebSocket    *WebSocket
	HijackConn   *HijackConn
	IsWebSocket  bool
	IsHijack     bool
	isEnd        bool //表示当前处理流程是否需要终止
	dotApp       *DotWeb
	HttpServer   *HttpServer
	SessionID    string
}

//reset response attr
func (ctx *HttpContext) Reset(res *Response, r *http.Request, server *HttpServer, params router.Params) {
	ctx.Request = r
	ctx.Response = res
	ctx.RouterParams = params
	ctx.IsHijack = false
	ctx.IsWebSocket = false
	ctx.HttpServer = server
	ctx.isEnd = false
}

//get application's global appcontext
//issue #3
func (ctx *HttpContext) AppContext() *AppContext {
	if ctx.HttpServer != nil {
		return ctx.HttpServer.DotApp.AppContext
	} else {
		return NewAppContext()
	}

}

//get session state in current context
func (ctx *HttpContext) Session() (session *session.SessionState) {
	if ctx.HttpServer == nil {
		//return nil, errors.New("no effective http-server")
		panic("no effective http-server")
	}
	if !ctx.HttpServer.ServerConfig.EnabledSession {
		//return nil, errors.New("http-server not enabled session")
		panic("http-server not enabled session")
	}
	state, err := ctx.HttpServer.sessionManager.GetSessionState(ctx.SessionID)
	if err != nil {
		panic(err.Error())
	}
	return state
}

//make current connection to hijack mode
func (ctx *HttpContext) Hijack() (*HijackConn, error) {
	hj, ok := ctx.Response.Writer().(http.Hijacker)
	if !ok {
		return nil, errors.New("The Web Server does not support Hijacking! ")
	}
	conn, bufrw, err := hj.Hijack()
	if err != nil {
		return nil, errors.New("Hijack error:" + err.Error())
	}
	ctx.HijackConn = &HijackConn{Conn: conn, ReadWriter: bufrw, header: "HTTP/1.1 200 OK\r\n"}
	ctx.IsHijack = true
	return ctx.HijackConn, nil
}

//set context process end
func (ctx *HttpContext) End() {
	ctx.isEnd = true
}

func (ctx *HttpContext) IsEnd() bool {
	return ctx.isEnd
}

//redirect replies to the request with a redirect to url
func (ctx *HttpContext) Redirect(targetUrl string) {
	http.Redirect(ctx.Response.Writer(), ctx.Request, targetUrl, http.StatusMovedPermanently)
}

/*
* 返回查询字符串map表示
 */
func (ctx *HttpContext) QueryStrings() url.Values {
	return ctx.Request.URL.Query()
}

/*
* 获取原始查询字符串
 */
func (ctx *HttpContext) RawQuery() string {
	return ctx.Request.URL.RawQuery
}

/*
* 根据指定key获取对应value
 */
func (ctx *HttpContext) QueryString(key string) string {
	return ctx.Request.URL.Query().Get(key)
}

/*
* 根据指定key获取包括在post、put和get内的值
 */
func (ctx *HttpContext) FormValue(key string) string {
	return ctx.Request.FormValue(key)
}

func (ctx *HttpContext) FormFile(key string) (*UploadFile, error) {
	file, header, err := ctx.Request.FormFile(key)
	if err != nil {
		return nil, err
	} else {
		return &UploadFile{
			File:   file,
			Header: header,
		}, nil
	}
}

/*
* 获取包括post、put和get内的值
 */
func (ctx *HttpContext) FormValues() map[string][]string {
	ctx.parseForm()
	return map[string][]string(ctx.Request.Form)
}

func (ctx *HttpContext) parseForm() error {
	if strings.HasPrefix(ctx.QueryHeader(echo.HeaderContentType), echo.MIMEMultipartForm) {
		if err := ctx.Request.ParseMultipartForm(defaultMemory); err != nil {
			return err
		}
	} else {
		if err := ctx.Request.ParseForm(); err != nil {
			return err
		}
	}
	return nil
}

/*
* 根据指定key获取包括在post、put内的值
 */
func (ctx *HttpContext) PostFormValue(key string) string {
	return ctx.Request.PostFormValue(key)
}

/*
* 根据指定key获取包括在post、put内的值
 */
func (ctx *HttpContext) PostString(key string) string {
	return ctx.Request.PostFormValue(key)
}

/*
* 获取post提交的字节数组
 */
func (ctx *HttpContext) PostBody() []byte {
	bts, err := ioutil.ReadAll(ctx.Request.Body)
	if err != nil {
		return []byte{}
	} else {
		return bts
	}
}

/*
* 支持Json、Xml、Form提交的属性绑定
 */
func (ctx *HttpContext) Bind(i interface{}) error {
	return ctx.HttpServer.Binder().Bind(i, ctx)
}

func (ctx *HttpContext) QueryHeader(key string) string {
	return ctx.Request.Header.Get(key)
}

func (ctx *HttpContext) DelHeader(key string) {
	ctx.Response.Header().Del(key)
}

//set response header kv info
func (ctx *HttpContext) SetHeader(key, value string) {
	if ctx.IsHijack {
		ctx.HijackConn.SetHeader(key, value)
	} else {
		ctx.Response.Header().Set(key, value)
	}
}

func (ctx *HttpContext) Url() string {
	return ctx.Request.URL.String()
}

func (ctx *HttpContext) ContentType() string {
	return ctx.Request.Header.Get(HeaderContentType)
}

func (ctx *HttpContext) GetRouterName(key string) string {
	return ctx.RouterParams.ByName(key)
}

// IsAJAX returns if it is a ajax request
func (ctx *HttpContext) IsAJAX() bool {
	return ctx.Request.Header.Get(HeaderXRequestedWith) == "XMLHttpRequest"
}

func (ctx *HttpContext) Proto() string {
	return ctx.Request.Proto
}

func (ctx *HttpContext) Method() string {
	return ctx.Request.Method
}

//RemoteAddr to an "IP" address
func (ctx *HttpContext) RemoteIP() string {
	fullIp := ctx.Request.RemoteAddr
	s := strings.Split(fullIp, ":")
	if len(s) > 1 {
		return s[0]
	} else {
		return fullIp
	}
}

//RemoteAddr to an "IP:port" address
func (ctx *HttpContext) FullRemoteIP() string {
	fullIp := ctx.Request.RemoteAddr
	return fullIp
}

// Referer returns request referer.
//
// The referer is valid until returning from RequestHandler.
func (ctx *HttpContext) Referer() string {
	return ctx.Request.Referer()
}

// UserAgent returns User-Agent header value from the request.
func (ctx *HttpContext) UserAgent() string {
	return ctx.Request.UserAgent()
}

// Path returns requested path.
//
// The path is valid until returning from RequestHandler.
func (ctx *HttpContext) Path() string {
	return ctx.Request.URL.Path
}

// Host returns requested host.
//
// The host is valid until returning from RequestHandler.
func (ctx *HttpContext) Host() string {
	return ctx.Request.Host
}

func (ctx *HttpContext) SetContentType(contenttype string) {
	ctx.SetHeader(HeaderContentType, contenttype)
}

func (ctx *HttpContext) SetStatusCode(code int) error {
	return ctx.Response.WriteHeader(code)
}

// write cookie for domain&name&liveseconds
//
// default path = "/"
// default domain = current domain
// default seconds = 0
func (ctx *HttpContext) WriteCookie(name, value string, seconds int) {
	cookie := http.Cookie{Name: name, Value: value, MaxAge: seconds}
	http.SetCookie(ctx.Response.Writer(), &cookie)
}

// write cookie with cookie-obj
func (ctx *HttpContext) WriteCookieObj(cookie http.Cookie) {
	http.SetCookie(ctx.Response.Writer(), &cookie)
}

// remove cookie for path&name
func (ctx *HttpContext) RemoveCookie(name string) {
	cookie := http.Cookie{Name: name, MaxAge: -1}
	http.SetCookie(ctx.Response.Writer(), &cookie)
}

// read cookie value for name
func (ctx *HttpContext) ReadCookie(name string) (string, error) {
	cookieobj, err := ctx.Request.Cookie(name)
	if err != nil {
		return "", err
	} else {
		return cookieobj.Value, nil
	}
}

// read cookie object for name
func (ctx *HttpContext) ReadCookieObj(name string) (*http.Cookie, error) {
	return ctx.Request.Cookie(name)
}

// write string content to response
func (ctx *HttpContext) WriteString(content string) (int, error) {
	if ctx.IsHijack {
		return ctx.HijackConn.WriteString(content)
	} else {
		return ctx.Response.Write([]byte(content))
	}
}

// write []byte content to response
func (ctx *HttpContext) WriteBlob(contentType string, b []byte) (int, error) {
	if contentType != "" {
		ctx.SetContentType(contentType)
	}
	if ctx.IsHijack {
		return ctx.HijackConn.WriteBlob(b)
	} else {
		return ctx.Response.Write(b)
	}
}

// write json string to response
//
// auto convert interface{} to json string
func (ctx *HttpContext) WriteJson(i interface{}) (int, error) {
	b, err := json.Marshal(i)
	if err != nil {
		return 0, err
	}
	return ctx.WriteJsonBlob(b)
}

// write json string as []byte to response
func (ctx *HttpContext) WriteJsonBlob(b []byte) (int, error) {
	return ctx.WriteBlob(MIMEApplicationJSONCharsetUTF8, b)
}

// write jsonp string to response
func (ctx *HttpContext) WriteJsonp(callback string, i interface{}) (int, error) {
	b, err := json.Marshal(i)
	if err != nil {
		return 0, err
	}
	return ctx.WriteJsonpBlob(callback, b)
}

// write jsonp string as []byte to response
func (ctx *HttpContext) WriteJsonpBlob(callback string, b []byte) (size int, err error) {
	ctx.SetContentType(MIMEApplicationJavaScriptCharsetUTF8)
	//特殊处理，如果为hijack，需要先行WriteBlob头部
	if ctx.IsHijack {
		if size, err = ctx.HijackConn.WriteBlob([]byte(ctx.HijackConn.header + "\r\n")); err != nil {
			return
		}
	}
	if size, err = ctx.WriteBlob("", []byte(callback+"(")); err != nil {
		return
	}
	if size, err = ctx.WriteBlob("", b); err != nil {
		return
	}
	size, err = ctx.WriteBlob("", []byte(");"))
	return
}
<commit_msg>* 新增HttpContext.Redirect() --fixed issue #4<commit_after>package dotweb

import (
	"encoding/json"
	"errors"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"

	"github.com/devfeel/dotweb/router"
	"github.com/devfeel/dotweb/session"
	"github.com/labstack/echo"
)

const (
	defaultMemory = 32 << 20 // 32 MB
)

type HttpContext struct {
	Request      *http.Request
	RouterParams router.Params
	Response     *Response
	WebSocket    *WebSocket
	HijackConn   *HijackConn
	IsWebSocket  bool
	IsHijack     bool
	isEnd        bool //表示当前处理流程是否需要终止
	dotApp       *DotWeb
	HttpServer   *HttpServer
	SessionID    string
}

//reset response attr
func (ctx *HttpContext) Reset(res *Response, r *http.Request, server *HttpServer, params router.Params) {
	ctx.Request = r
	ctx.Response = res
	ctx.RouterParams = params
	ctx.IsHijack = false
	ctx.IsWebSocket = false
	ctx.HttpServer = server
	ctx.isEnd = false
}

//get application's global appcontext
//issue #3
func (ctx *HttpContext) AppContext() *AppContext {
	if ctx.HttpServer != nil {
		return ctx.HttpServer.DotApp.AppContext
	} else {
		return NewAppContext()
	}

}

//get session state in current context
func (ctx *HttpContext) Session() (session *session.SessionState) {
	if ctx.HttpServer == nil {
		//return nil, errors.New("no effective http-server")
		panic("no effective http-server")
	}
	if !ctx.HttpServer.ServerConfig.EnabledSession {
		//return nil, errors.New("http-server not enabled session")
		panic("http-server not enabled session")
	}
	state, err := ctx.HttpServer.sessionManager.GetSessionState(ctx.SessionID)
	if err != nil {
		panic(err.Error())
	}
	return state
}

//make current connection to hijack mode
func (ctx *HttpContext) Hijack() (*HijackConn, error) {
	hj, ok := ctx.Response.Writer().(http.Hijacker)
	if !ok {
		return nil, errors.New("The Web Server does not support Hijacking! ")
	}
	conn, bufrw, err := hj.Hijack()
	if err != nil {
		return nil, errors.New("Hijack error:" + err.Error())
	}
	ctx.HijackConn = &HijackConn{Conn: conn, ReadWriter: bufrw, header: "HTTP/1.1 200 OK\r\n"}
	ctx.IsHijack = true
	return ctx.HijackConn, nil
}

//set context process end
func (ctx *HttpContext) End() {
	ctx.isEnd = true
}

func (ctx *HttpContext) IsEnd() bool {
	return ctx.isEnd
}

//redirect replies to the request with a redirect to url
//default use 301
func (ctx *HttpContext) Redirect(targetUrl string) {
	http.Redirect(ctx.Response.Writer(), ctx.Request, targetUrl, http.StatusMovedPermanently)
}

/*
* 返回查询字符串map表示
 */
func (ctx *HttpContext) QueryStrings() url.Values {
	return ctx.Request.URL.Query()
}

/*
* 获取原始查询字符串
 */
func (ctx *HttpContext) RawQuery() string {
	return ctx.Request.URL.RawQuery
}

/*
* 根据指定key获取对应value
 */
func (ctx *HttpContext) QueryString(key string) string {
	return ctx.Request.URL.Query().Get(key)
}

/*
* 根据指定key获取包括在post、put和get内的值
 */
func (ctx *HttpContext) FormValue(key string) string {
	return ctx.Request.FormValue(key)
}

func (ctx *HttpContext) FormFile(key string) (*UploadFile, error) {
	file, header, err := ctx.Request.FormFile(key)
	if err != nil {
		return nil, err
	} else {
		return &UploadFile{
			File:   file,
			Header: header,
		}, nil
	}
}

/*
* 获取包括post、put和get内的值
 */
func (ctx *HttpContext) FormValues() map[string][]string {
	ctx.parseForm()
	return map[string][]string(ctx.Request.Form)
}

func (ctx *HttpContext) parseForm() error {
	if strings.HasPrefix(ctx.QueryHeader(echo.HeaderContentType), echo.MIMEMultipartForm) {
		if err := ctx.Request.ParseMultipartForm(defaultMemory); err != nil {
			return err
		}
	} else {
		if err := ctx.Request.ParseForm(); err != nil {
			return err
		}
	}
	return nil
}

/*
* 根据指定key获取包括在post、put内的值
 */
func (ctx *HttpContext) PostFormValue(key string) string {
	return ctx.Request.PostFormValue(key)
}

/*
* 根据指定key获取包括在post、put内的值
 */
func (ctx *HttpContext) PostString(key string) string {
	return ctx.Request.PostFormValue(key)
}

/*
* 获取post提交的字节数组
 */
func (ctx *HttpContext) PostBody() []byte {
	bts, err := ioutil.ReadAll(ctx.Request.Body)
	if err != nil {
		return []byte{}
	} else {
		return bts
	}
}

/*
* 支持Json、Xml、Form提交的属性绑定
 */
func (ctx *HttpContext) Bind(i interface{}) error {
	return ctx.HttpServer.Binder().Bind(i, ctx)
}

func (ctx *HttpContext) QueryHeader(key string) string {
	return ctx.Request.Header.Get(key)
}

func (ctx *HttpContext) DelHeader(key string) {
	ctx.Response.Header().Del(key)
}

//set response header kv info
func (ctx *HttpContext) SetHeader(key, value string) {
	if ctx.IsHijack {
		ctx.HijackConn.SetHeader(key, value)
	} else {
		ctx.Response.Header().Set(key, value)
	}
}

func (ctx *HttpContext) Url() string {
	return ctx.Request.URL.String()
}

func (ctx *HttpContext) ContentType() string {
	return ctx.Request.Header.Get(HeaderContentType)
}

func (ctx *HttpContext) GetRouterName(key string) string {
	return ctx.RouterParams.ByName(key)
}

// IsAJAX returns if it is a ajax request
func (ctx *HttpContext) IsAJAX() bool {
	return ctx.Request.Header.Get(HeaderXRequestedWith) == "XMLHttpRequest"
}

func (ctx *HttpContext) Proto() string {
	return ctx.Request.Proto
}

func (ctx *HttpContext) Method() string {
	return ctx.Request.Method
}

//RemoteAddr to an "IP" address
func (ctx *HttpContext) RemoteIP() string {
	fullIp := ctx.Request.RemoteAddr
	s := strings.Split(fullIp, ":")
	if len(s) > 1 {
		return s[0]
	} else {
		return fullIp
	}
}

//RemoteAddr to an "IP:port" address
func (ctx *HttpContext) FullRemoteIP() string {
	fullIp := ctx.Request.RemoteAddr
	return fullIp
}

// Referer returns request referer.
//
// The referer is valid until returning from RequestHandler.
func (ctx *HttpContext) Referer() string {
	return ctx.Request.Referer()
}

// UserAgent returns User-Agent header value from the request.
func (ctx *HttpContext) UserAgent() string {
	return ctx.Request.UserAgent()
}

// Path returns requested path.
//
// The path is valid until returning from RequestHandler.
func (ctx *HttpContext) Path() string {
	return ctx.Request.URL.Path
}

// Host returns requested host.
//
// The host is valid until returning from RequestHandler.
func (ctx *HttpContext) Host() string {
	return ctx.Request.Host
}

func (ctx *HttpContext) SetContentType(contenttype string) {
	ctx.SetHeader(HeaderContentType, contenttype)
}

func (ctx *HttpContext) SetStatusCode(code int) error {
	return ctx.Response.WriteHeader(code)
}

// write cookie for domain&name&liveseconds
//
// default path = "/"
// default domain = current domain
// default seconds = 0
func (ctx *HttpContext) WriteCookie(name, value string, seconds int) {
	cookie := http.Cookie{Name: name, Value: value, MaxAge: seconds}
	http.SetCookie(ctx.Response.Writer(), &cookie)
}

// write cookie with cookie-obj
func (ctx *HttpContext) WriteCookieObj(cookie http.Cookie) {
	http.SetCookie(ctx.Response.Writer(), &cookie)
}

// remove cookie for path&name
func (ctx *HttpContext) RemoveCookie(name string) {
	cookie := http.Cookie{Name: name, MaxAge: -1}
	http.SetCookie(ctx.Response.Writer(), &cookie)
}

// read cookie value for name
func (ctx *HttpContext) ReadCookie(name string) (string, error) {
	cookieobj, err := ctx.Request.Cookie(name)
	if err != nil {
		return "", err
	} else {
		return cookieobj.Value, nil
	}
}

// read cookie object for name
func (ctx *HttpContext) ReadCookieObj(name string) (*http.Cookie, error) {
	return ctx.Request.Cookie(name)
}

// write string content to response
func (ctx *HttpContext) WriteString(content string) (int, error) {
	if ctx.IsHijack {
		return ctx.HijackConn.WriteString(content)
	} else {
		return ctx.Response.Write([]byte(content))
	}
}

// write []byte content to response
func (ctx *HttpContext) WriteBlob(contentType string, b []byte) (int, error) {
	if contentType != "" {
		ctx.SetContentType(contentType)
	}
	if ctx.IsHijack {
		return ctx.HijackConn.WriteBlob(b)
	} else {
		return ctx.Response.Write(b)
	}
}

// write json string to response
//
// auto convert interface{} to json string
func (ctx *HttpContext) WriteJson(i interface{}) (int, error) {
	b, err := json.Marshal(i)
	if err != nil {
		return 0, err
	}
	return ctx.WriteJsonBlob(b)
}

// write json string as []byte to response
func (ctx *HttpContext) WriteJsonBlob(b []byte) (int, error) {
	return ctx.WriteBlob(MIMEApplicationJSONCharsetUTF8, b)
}

// write jsonp string to response
func (ctx *HttpContext) WriteJsonp(callback string, i interface{}) (int, error) {
	b, err := json.Marshal(i)
	if err != nil {
		return 0, err
	}
	return ctx.WriteJsonpBlob(callback, b)
}

// write jsonp string as []byte to response
func (ctx *HttpContext) WriteJsonpBlob(callback string, b []byte) (size int, err error) {
	ctx.SetContentType(MIMEApplicationJavaScriptCharsetUTF8)
	//特殊处理，如果为hijack，需要先行WriteBlob头部
	if ctx.IsHijack {
		if size, err = ctx.HijackConn.WriteBlob([]byte(ctx.HijackConn.header + "\r\n")); err != nil {
			return
		}
	}
	if size, err = ctx.WriteBlob("", []byte(callback+"(")); err != nil {
		return
	}
	if size, err = ctx.WriteBlob("", b); err != nil {
		return
	}
	size, err = ctx.WriteBlob("", []byte(");"))
	return
}
<|endoftext|>